From dd875987b92b7496c8424112026a600f7631bb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Fri, 8 Dec 2023 19:00:10 +0100 Subject: [PATCH 01/12] Enable basic rendering of custom elements in secondary Renderers By factoring element and other static-ish data out of Simulation and protecting basic graphical element properties (i.e. everything that contributes to graphics other than the Graphics callback) with an std::shared_mutex. This is taken exclusively (std::unique_lock) by the main thread when it changes these properties, and inclusively (std::shared_lock) by non-main-thread code that uses Renderer. --- src/PowderToy.cpp | 3 + src/PowderToyRenderer.cpp | 2 + src/client/GameSave.cpp | 10 +- src/common/ExplicitSingleton.h | 5 + src/debug/ElementPopulation.cpp | 12 +- src/graphics/Renderer.cpp | 26 +- src/graphics/Renderer.h | 2 + src/gui/game/GOLTool.cpp | 5 +- src/gui/game/GameController.cpp | 33 +- src/gui/game/GameModel.cpp | 39 +-- src/gui/game/PropertyTool.cpp | 8 +- src/lua/LegacyLuaAPI.cpp | 54 ++-- src/lua/LuaScriptInterface.cpp | 486 +++++++++++++++++------------- src/lua/TPTScriptInterface.cpp | 13 +- src/simulation/Air.cpp | 4 +- src/simulation/BuiltinGOL.h | 3 +- src/simulation/Editing.cpp | 28 +- src/simulation/Element.cpp | 12 +- src/simulation/ElementClasses.cpp | 6 +- src/simulation/ElementClasses.h | 4 +- src/simulation/ElementCommon.h | 1 + src/simulation/SaveRenderer.cpp | 4 + src/simulation/Sign.cpp | 8 +- src/simulation/Simulation.cpp | 264 +++------------- src/simulation/Simulation.h | 48 +-- src/simulation/SimulationData.cpp | 259 +++++++++++++++- src/simulation/SimulationData.h | 73 ++++- src/simulation/elements/ACEL.cpp | 4 +- src/simulation/elements/ACID.cpp | 6 +- src/simulation/elements/ARAY.cpp | 4 +- src/simulation/elements/BCLN.cpp | 6 +- src/simulation/elements/BTRY.cpp | 4 +- src/simulation/elements/C5.cpp | 4 +- src/simulation/elements/CAUS.cpp | 6 +- src/simulation/elements/CBNW.cpp | 6 +- src/simulation/elements/CLNE.cpp | 6 +- src/simulation/elements/CONV.cpp | 6 +- src/simulation/elements/CRAY.cpp | 8 +- src/simulation/elements/DCEL.cpp | 4 +- src/simulation/elements/DEST.cpp | 6 +- src/simulation/elements/DMG.cpp | 6 +- src/simulation/elements/DRAY.cpp | 4 +- src/simulation/elements/DTEC.cpp | 4 +- src/simulation/elements/ELEC.cpp | 4 +- src/simulation/elements/EMBR.cpp | 4 +- src/simulation/elements/FIGH.cpp | 6 +- src/simulation/elements/FIRE.cpp | 24 +- src/simulation/elements/FIRW.cpp | 8 +- src/simulation/elements/FOG.cpp | 4 +- src/simulation/elements/FRAY.cpp | 4 +- src/simulation/elements/FWRK.cpp | 8 +- src/simulation/elements/GEL.cpp | 8 +- src/simulation/elements/H2.cpp | 4 +- src/simulation/elements/HEAC.cpp | 13 +- src/simulation/elements/ICEI.cpp | 4 +- src/simulation/elements/LDTC.cpp | 4 +- src/simulation/elements/LIFE.cpp | 5 +- src/simulation/elements/LIGH.cpp | 16 +- src/simulation/elements/LSNS.cpp | 4 +- src/simulation/elements/NBLE.cpp | 4 +- src/simulation/elements/O2.cpp | 4 +- src/simulation/elements/PBCN.cpp | 8 +- src/simulation/elements/PCLN.cpp | 8 +- src/simulation/elements/PIPE.cpp | 22 +- src/simulation/elements/PROT.cpp | 8 +- src/simulation/elements/PRTI.cpp | 6 +- src/simulation/elements/PSNS.cpp | 4 +- src/simulation/elements/RPEL.cpp | 4 +- src/simulation/elements/SOAP.cpp | 4 +- src/simulation/elements/SPRK.cpp | 6 +- src/simulation/elements/STKM.cpp | 26 +- src/simulation/elements/STOR.cpp | 10 +- src/simulation/elements/THDR.cpp | 4 +- src/simulation/elements/TRON.cpp | 4 +- src/simulation/elements/TSNS.cpp | 4 +- src/simulation/elements/TUNG.cpp | 8 +- src/simulation/elements/VIBR.cpp | 6 +- src/simulation/elements/VSNS.cpp | 12 +- src/simulation/simtools/MIX.cpp | 6 +- 79 files changed, 1038 insertions(+), 736 deletions(-) diff --git a/src/PowderToy.cpp b/src/PowderToy.cpp index 42b364699..39e62dba4 100644 --- a/src/PowderToy.cpp +++ b/src/PowderToy.cpp @@ -12,6 +12,7 @@ #include "common/platform/Platform.h" #include "graphics/Graphics.h" #include "simulation/SaveRenderer.h" +#include "simulation/SimulationData.h" #include "common/tpt-rand.h" #include "gui/game/Favorite.h" #include "gui/Style.h" @@ -180,6 +181,7 @@ struct ExplicitSingletons std::unique_ptr saveRenderer; std::unique_ptr favorite; std::unique_ptr engine; + std::unique_ptr simulationData; std::unique_ptr gameController; }; static std::unique_ptr explicitSingletons; @@ -416,6 +418,7 @@ int Main(int argc, char *argv[]) } auto wrapWithBluescreen = [&]() { + explicitSingletons->simulationData = std::make_unique(); explicitSingletons->gameController = std::make_unique(); auto *gameController = explicitSingletons->gameController.get(); engine.ShowWindow(gameController->GetView()); diff --git a/src/PowderToyRenderer.cpp b/src/PowderToyRenderer.cpp index 78a3d91f1..d7c35aed4 100644 --- a/src/PowderToyRenderer.cpp +++ b/src/PowderToyRenderer.cpp @@ -6,6 +6,7 @@ #include "gui/interface/Engine.h" #include "client/GameSave.h" #include "simulation/Simulation.h" +#include "simulation/SimulationData.h" #include "common/platform/Platform.h" #include #include @@ -39,6 +40,7 @@ int main(int argc, char *argv[]) throw e; } + auto simulationData = std::make_unique(); Simulation * sim = new Simulation(); Renderer * ren = new Renderer(sim); diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 294aac63d..3d08d48ca 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -328,6 +328,7 @@ static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *se void GameSave::readOPS(const std::vector &data) { + auto &builtinGol = SimulationData::builtinGol; constexpr auto currentVersion = Version(currentVersionMajor, 0); constexpr auto nextVersion = Version(nextVersionMajor, 0); @@ -1185,6 +1186,7 @@ void GameSave::readOPS(const std::vector &data) #define MTOS(str) MTOS_EXPAND(str) void GameSave::readPSv(const std::vector &dataVec) { + auto &builtinGol = SimulationData::builtinGol; Renderer::PopulateTables(); unsigned char * saveData = (unsigned char *)&dataVec[0]; @@ -1197,7 +1199,7 @@ void GameSave::readPSv(const std::vector &dataVec) char tempSignText[255]; sign tempSign("", 0, 0, sign::Left); - auto &elements = GetElements(); + auto &builtinElements = GetElements(); //New file header uses PSv, replacing fuC. This is to detect if the client uses a new save format for temperatures //This creates a problem for old clients, that display and "corrupt" error instead of a "newer version" error @@ -1607,7 +1609,7 @@ void GameSave::readPSv(const std::vector &dataVec) } else { - particles[i-1].temp = elements[particles[i-1].type].DefaultProperties.temp; + particles[i-1].temp = builtinElements[particles[i-1].type].DefaultProperties.temp; } } } @@ -1970,7 +1972,7 @@ std::pair> GameSave::serialiseOPS() const That way, if we ever need a 25th bit, we won't have to change the save format */ - auto &elements = GetElements(); + auto &builtinElements = GetElements(); auto &possiblyCarriesType = Particle::PossiblyCarriesType(); auto &properties = Particle::GetProperties(); // Allocate enough space to store all Particles and 3 bytes on top of that per Particle, for the field descriptors. @@ -2200,7 +2202,7 @@ std::pair> GameSave::serialiseOPS() const { for (auto index : possiblyCarriesType) { - if (elements[particles[i].type].CarriesTypeIn & (1U << index)) + if (builtinElements[particles[i].type].CarriesTypeIn & (1U << index)) { auto *prop = reinterpret_cast(reinterpret_cast(&particles[i]) + properties[index].Offset); if (TYP(*prop) > 0xFF) diff --git a/src/common/ExplicitSingleton.h b/src/common/ExplicitSingleton.h index a21887b76..715a0c4bd 100644 --- a/src/common/ExplicitSingleton.h +++ b/src/common/ExplicitSingleton.h @@ -28,4 +28,9 @@ public: { return *Instance(); } + + static const Type &CRef() + { + return Ref(); + } }; diff --git a/src/debug/ElementPopulation.cpp b/src/debug/ElementPopulation.cpp index 76ec04133..0f5849d73 100644 --- a/src/debug/ElementPopulation.cpp +++ b/src/debug/ElementPopulation.cpp @@ -1,9 +1,7 @@ #include "ElementPopulation.h" - #include "gui/interface/Engine.h" - #include "simulation/Simulation.h" - +#include "simulation/SimulationData.h" #include "graphics/Graphics.h" ElementPopulationDebug::ElementPopulationDebug(unsigned int id, Simulation * sim): @@ -16,6 +14,8 @@ ElementPopulationDebug::ElementPopulationDebug(unsigned int id, Simulation * sim void ElementPopulationDebug::Draw() { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; Graphics * g = ui::Engine::Ref().g; int yBottom = YRES-10; @@ -30,7 +30,7 @@ void ElementPopulationDebug::Draw() int bars = 0; for(int i = 0; i < PT_NUM; i++) { - if(sim->elements[i].Enabled) + if(elements[i].Enabled) { if(maxVal < sim->elementCount[i]) maxVal = float(sim->elementCount[i]); @@ -49,13 +49,13 @@ void ElementPopulationDebug::Draw() bars = 0; for(int i = 0; i < PT_NUM; i++) { - if(sim->elements[i].Enabled) + if(elements[i].Enabled) { auto count = sim->elementCount[i]; auto barSize = int(count * scale - 0.5f); int barX = bars;//*2; - RGB colour = sim->elements[i].Colour; + RGB colour = elements[i].Colour; g->DrawLine({ xStart+barX, yBottom+3 }, { xStart+barX, yBottom+2 }, colour); if(sim->elementCount[i]) diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 07e1fb1be..9179d52cc 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -11,7 +11,8 @@ std::unique_ptr Renderer::WallIcon(int wallID, Vec2 size) { - auto wtypes = LoadWalls(); + auto &sd = SimulationData::CRef(); + auto &wtypes = sd.wtypes; if (wallID < 0 || wallID >= int(wtypes.size())) return nullptr; wall_type const &wtype = wtypes[wallID]; @@ -170,14 +171,14 @@ void Renderer::DrawSigns() void Renderer::render_parts() { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y; int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0}; Particle * parts; - Element *elements; if(!sim) return; parts = sim->parts; - elements = sim->elements.data(); if (gridSize)//draws the grid { for (ny=0; ny= XRES || nx < 0 || ny >= YRES || ny < 0) continue; - if(TYP(sim->photons[ny][nx]) && !(sim->elements[t].Properties & TYPE_ENERGY) && t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH) + if(TYP(sim->photons[ny][nx]) && !(elements[t].Properties & TYPE_ENERGY) && t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH) continue; //Defaults @@ -242,7 +243,8 @@ void Renderer::render_parts() } else if(!(colour_mode & COLOUR_BASC)) { - if (!elements[t].Graphics || (*(elements[t].Graphics))(this, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb)) //That's a lot of args, a struct might be better + auto *graphics = useGraphicsFunction ? elements[t].Graphics : nullptr; + if (!graphics || graphics(this, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb)) //That's a lot of args, a struct might be better { graphicscache[t].isready = 1; graphicscache[t].pixel_mode = pixel_mode; @@ -927,6 +929,8 @@ void Renderer::draw_air() void Renderer::DrawWalls() { + auto &sd = SimulationData::CRef(); + auto &wtypes = sd.wtypes; for (int y = 0; y < YCELLS; y++) for (int x =0; x < XCELLS; x++) if (sim->bmap[y][x]) @@ -935,8 +939,8 @@ void Renderer::DrawWalls() if (wt >= UI_WALLCOUNT) continue; unsigned char powered = sim->emap[y][x]; - RGB prgb = sim->wtypes[wt].colour; - RGB grgb = sim->wtypes[wt].eglow; + RGB prgb = wtypes[wt].colour; + RGB grgb = wtypes[wt].eglow; if (findingElement) { @@ -951,7 +955,7 @@ void Renderer::DrawWalls() pixel pc = prgb.Pack(); pixel gc = grgb.Pack(); - switch (sim->wtypes[wt].drawstyle) + switch (wtypes[wt].drawstyle) { case 0: if (wt == WL_EWALL || wt == WL_STASIS) @@ -1075,7 +1079,7 @@ void Renderer::DrawWalls() // when in blob view, draw some blobs... if (render_mode & PMODE_BLOB) { - switch (sim->wtypes[wt].drawstyle) + switch (wtypes[wt].drawstyle) { case 0: if (wt == WL_EWALL || wt == WL_STASIS) @@ -1156,10 +1160,10 @@ void Renderer::DrawWalls() } } - if (sim->wtypes[wt].eglow.Pack() && powered) + if (wtypes[wt].eglow.Pack() && powered) { // glow if electrified - RGB glow = sim->wtypes[wt].eglow; + RGB glow = wtypes[wt].eglow; int alpha = 255; int cr = (alpha*glow.Red + (255-alpha)*fire_r[y/CELL][x/CELL]) >> 8; int cg = (alpha*glow.Green + (255-alpha)*fire_g[y/CELL][x/CELL]) >> 8; diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index e0db7cfcb..d1f2b0909 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -167,6 +167,8 @@ public: #undef RENDERER_TABLE static void PopulateTables(); + bool useGraphicsFunction = false; + private: int gridSize; }; diff --git a/src/gui/game/GOLTool.cpp b/src/gui/game/GOLTool.cpp index 19381f19c..c44a48b58 100644 --- a/src/gui/game/GOLTool.cpp +++ b/src/gui/game/GOLTool.cpp @@ -4,7 +4,7 @@ #include "client/Client.h" #include "common/tpt-rand.h" #include "simulation/GOLString.h" -#include "simulation/Simulation.h" +#include "simulation/SimulationData.h" #include "gui/Style.h" #include "gui/interface/Button.h" @@ -135,6 +135,7 @@ void GOLWindow::updateGradient() void GOLWindow::validate() { + auto &sd = SimulationData::CRef(); auto nameString = nameField->GetText(); auto ruleString = ruleField->GetText(); if (!ValidateGOLName(nameString)) @@ -149,7 +150,7 @@ void GOLWindow::validate() new ErrorMessage("Could not add GOL type", "Invalid rule provided"); return; } - if (sim->GetCustomGOLByRule(rule)) + if (sd.GetCustomGOLByRule(rule)) { new ErrorMessage("Could not add GOL type", "This Custom GoL rule already exists"); return; diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index add450109..33b5640a4 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -757,11 +757,12 @@ void GameController::ResetAir() void GameController::ResetSpark() { + auto &sd = SimulationData::CRef(); Simulation * sim = gameModel->GetSimulation(); for (int i = 0; i < NPART; i++) if (sim->parts[i].type == PT_SPRK) { - if (sim->parts[i].ctype >= 0 && sim->parts[i].ctype < PT_NUM && sim->elements[sim->parts[i].ctype].Enabled) + if (sim->parts[i].ctype >= 0 && sim->parts[i].ctype < PT_NUM && sd.elements[sim->parts[i].ctype].Enabled) { sim->parts[i].type = sim->parts[i].ctype; sim->parts[i].ctype = sim->parts[i].life = 0; @@ -849,6 +850,7 @@ void GameController::LoadRenderPreset(int presetNum) void GameController::Update() { + auto &sd = SimulationData::CRef(); ui::Point pos = gameView->GetMousePosition(); gameModel->GetRenderer()->mousePos = PointTranslate(pos); if (pos.X < XRES && pos.Y < YRES) @@ -875,7 +877,7 @@ void GameController::Update() if (activeTool->Identifier.BeginsWith("DEFAULT_PT_")) { int sr = activeTool->ToolID; - if (sr && sim->IsElementOrNone(sr)) + if (sr && sd.IsElementOrNone(sr)) rightSelected = sr; } @@ -1497,20 +1499,14 @@ String GameController::ElementResolve(int type, int ctype) // "NONE" should never be displayed in the HUD if (!type) return ""; - if (gameModel && gameModel->GetSimulation()) - { - return gameModel->GetSimulation()->ElementResolve(type, ctype); - } - return ""; + auto &sd = SimulationData::CRef(); + return sd.ElementResolve(type, ctype); } String GameController::BasicParticleInfo(Particle const &sample_part) { - if (gameModel && gameModel->GetSimulation()) - { - return gameModel->GetSimulation()->BasicParticleInfo(sample_part); - } - return ""; + auto &sd = SimulationData::CRef(); + return sd.BasicParticleInfo(sample_part); } void GameController::ReloadSim() @@ -1529,18 +1525,15 @@ void GameController::ReloadSim() bool GameController::IsValidElement(int type) { - if (gameModel && gameModel->GetSimulation()) - { - return (type && gameModel->GetSimulation()->IsElement(type)); - } - else - return false; + auto &sd = SimulationData::CRef(); + return type && sd.IsElement(type); } String GameController::WallName(int type) { - if(gameModel && gameModel->GetSimulation() && type >= 0 && type < UI_WALLCOUNT) - return gameModel->GetSimulation()->wtypes[type].name; + auto &sd = SimulationData::CRef(); + if(type >= 0 && type < UI_WALLCOUNT) + return sd.wtypes[type].name; else return String(); } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 81250ff6e..92b93904d 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -57,6 +57,7 @@ GameModel::GameModel(): { sim = new Simulation(); ren = new Renderer(sim); + ren->useGraphicsFunction = true; activeTools = regularToolset; @@ -219,6 +220,9 @@ void GameModel::BuildQuickOptionMenu(GameController * controller) void GameModel::BuildMenus() { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; + auto &builtinGol = SimulationData::builtinGol; int lastMenu = -1; if(activeMenu != -1) lastMenu = activeMenu; @@ -253,35 +257,35 @@ void GameModel::BuildMenus() //Create menus for (int i = 0; i < SC_TOTAL; i++) { - menuList.push_back(new Menu(sim->msections[i].icon, sim->msections[i].name, sim->msections[i].doshow)); + menuList.push_back(new Menu(sd.msections[i].icon, sd.msections[i].name, sd.msections[i].doshow)); } //Build menus from Simulation elements for(int i = 0; i < PT_NUM; i++) { - if(sim->elements[i].Enabled) + if(elements[i].Enabled) { Tool * tempTool; if(i == PT_LIGH) { - tempTool = new Element_LIGH_Tool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator); + tempTool = new Element_LIGH_Tool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator); } else if(i == PT_TESC) { - tempTool = new Element_TESC_Tool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator); + tempTool = new Element_TESC_Tool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator); } else if(i == PT_STKM || i == PT_FIGH || i == PT_STKM2) { - tempTool = new PlopTool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator); + tempTool = new PlopTool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator); } else { - tempTool = new ElementTool(i, sim->elements[i].Name, sim->elements[i].Description, sim->elements[i].Colour, sim->elements[i].Identifier, sim->elements[i].IconGenerator); + tempTool = new ElementTool(i, elements[i].Name, elements[i].Description, elements[i].Colour, elements[i].Identifier, elements[i].IconGenerator); } - if (sim->elements[i].MenuSection >= 0 && sim->elements[i].MenuSection < SC_TOTAL && sim->elements[i].MenuVisible) + if (elements[i].MenuSection >= 0 && elements[i].MenuSection < SC_TOTAL && elements[i].MenuVisible) { - menuList[sim->elements[i].MenuSection]->AddTool(tempTool); + menuList[elements[i].MenuSection]->AddTool(tempTool); } else { @@ -301,7 +305,7 @@ void GameModel::BuildMenus() auto &prefs = GlobalPrefs::Ref(); auto customGOLTypes = prefs.Get("CustomGOL.Types", std::vector{}); std::vector validatedCustomLifeTypes; - std::vector newCustomGol; + std::vector newCustomGol; bool removedAny = false; for (auto gol : customGOLTypes) { @@ -311,7 +315,7 @@ void GameModel::BuildMenus() removedAny = true; continue; } - Simulation::CustomGOLData gd; + CustomGOLData gd; gd.nameString = parts[0]; gd.ruleString = parts[1]; auto &colour1String = parts[2]; @@ -350,26 +354,25 @@ void GameModel::BuildMenus() Tool * tempTool = new ElementTool(PT_LIFE|PMAPID(gd.rule), gd.nameString, "Custom GOL type: " + gd.ruleString, RGB::Unpack(gd.colour1), "DEFAULT_PT_LIFECUST_"+gd.nameString.ToAscii(), NULL); menuList[SC_LIFE]->AddTool(tempTool); } - sim->SetCustomGOL(newCustomGol); + sd.SetCustomGOL(newCustomGol); } //Build other menus from wall data for(int i = 0; i < UI_WALLCOUNT; i++) { - Tool * tempTool = new WallTool(i, sim->wtypes[i].descs, sim->wtypes[i].colour, sim->wtypes[i].identifier, sim->wtypes[i].textureGen); + Tool * tempTool = new WallTool(i, sd.wtypes[i].descs, sd.wtypes[i].colour, sd.wtypes[i].identifier, sd.wtypes[i].textureGen); menuList[SC_WALL]->AddTool(tempTool); - //sim->wtypes[i] } //Build menu for tools - for (size_t i = 0; i < sim->tools.size(); i++) + for (size_t i = 0; i < sd.tools.size(); i++) { Tool *tempTool = new Tool( i, - sim->tools[i].Name, - sim->tools[i].Description, - sim->tools[i].Colour, - sim->tools[i].Identifier + sd.tools[i].Name, + sd.tools[i].Description, + sd.tools[i].Colour, + sd.tools[i].Identifier ); menuList[SC_TOOL]->AddTool(tempTool); } diff --git a/src/gui/game/PropertyTool.cpp b/src/gui/game/PropertyTool.cpp index eb3f8a794..36b80d659 100644 --- a/src/gui/game/PropertyTool.cpp +++ b/src/gui/game/PropertyTool.cpp @@ -114,6 +114,8 @@ void PropertyWindow::Update() void PropertyWindow::CheckProperty() { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; configuration.reset(); PropertyTool::Configuration newConfiguration; if (!(property->GetOption().second!=-1 && textField->GetText().length() > 0)) @@ -142,7 +144,7 @@ void PropertyWindow::CheckProperty() else { // Try to parse as particle name - v = sim->GetParticleType(value.ToUtf8()); + v = sd.GetParticleType(value.ToUtf8()); // Try to parse special GoL rules if (v == -1 && properties[property->GetOption().second].Name == "ctype") @@ -160,7 +162,7 @@ void PropertyWindow::CheckProperty() } else { - v = sim->GetParticleType(value.ToUtf8()); + v = sd.GetParticleType(value.ToUtf8()); if (v == -1) { for (auto *elementTool : tool->gameModel.GetMenuList()[SC_LIFE]->GetToolList()) @@ -182,7 +184,7 @@ void PropertyWindow::CheckProperty() } } - if (properties[property->GetOption().second].Name == "type" && (v < 0 || v >= PT_NUM || !sim->elements[v].Enabled)) + if (properties[property->GetOption().second].Name == "type" && (v < 0 || v >= PT_NUM || !elements[v].Enabled)) { return; } diff --git a/src/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index 32e009e16..93dd81006 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -152,6 +152,8 @@ int luacon_partswrite(lua_State* l) int luacon_transitionread(lua_State* l) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; ByteString key = tpt_lua_optByteString(l, 2, ""); if (legacyTransitionNames.find(key) == legacyTransitionNames.end()) return luaL_error(l, "Invalid property"); @@ -162,12 +164,12 @@ int luacon_transitionread(lua_State* l) lua_rawget(l, 1); int i = lua_tointeger (l, lua_gettop(l)); lua_pop(l, 1); - if (!luacon_sim->IsElement(i)) + if (!sd.IsElement(i)) { return luaL_error(l, "Invalid index"); } - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset); + intptr_t propertyAddress = (intptr_t)(((const unsigned char*)&elements[i]) + prop.Offset); LuaScriptInterface::LuaGetProperty(l, prop, propertyAddress); return 1; @@ -175,6 +177,8 @@ int luacon_transitionread(lua_State* l) int luacon_transitionwrite(lua_State* l) { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; ByteString key = tpt_lua_optByteString(l, 2, ""); if (legacyTransitionNames.find(key) == legacyTransitionNames.end()) return luaL_error(l, "Invalid property"); @@ -185,7 +189,7 @@ int luacon_transitionwrite(lua_State* l) lua_rawget(l, 1); int i = lua_tointeger (l, lua_gettop(l)); lua_pop(l, 1); - if (!luacon_sim->IsElement(i)) + if (!sd.IsElement(i)) { return luaL_error(l, "Invalid index"); } @@ -193,13 +197,13 @@ int luacon_transitionwrite(lua_State* l) if (prop.Type == StructProperty::TransitionType) { int type = luaL_checkinteger(l, 3); - if (!luacon_sim->IsElementOrNone(type) && type != NT && type != ST) + if (!sd.IsElementOrNone(type) && type != NT && type != ST) { return luaL_error(l, "Invalid element"); } } - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset); + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[i]) + prop.Offset); LuaScriptInterface::LuaSetProperty(l, prop, propertyAddress, 3); return 0; @@ -207,6 +211,8 @@ int luacon_transitionwrite(lua_State* l) int luacon_elementread(lua_State* l) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; ByteString key = tpt_lua_optByteString(l, 2, ""); if (legacyPropNames.find(key) == legacyPropNames.end()) return luaL_error(l, "Invalid property"); @@ -217,12 +223,12 @@ int luacon_elementread(lua_State* l) lua_rawget(l, 1); int i = lua_tointeger (l, lua_gettop(l)); lua_pop(l, 1); - if (!luacon_sim->IsElement(i)) + if (!sd.IsElement(i)) { return luaL_error(l, "Invalid index"); } - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset); + intptr_t propertyAddress = (intptr_t)(((const unsigned char*)&elements[i]) + prop.Offset); LuaScriptInterface::LuaGetProperty(l, prop, propertyAddress); return 1; @@ -230,6 +236,9 @@ int luacon_elementread(lua_State* l) int luacon_elementwrite(lua_State* l) { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; ByteString key = tpt_lua_optByteString(l, 2, ""); if (legacyPropNames.find(key) == legacyPropNames.end()) return luaL_error(l, "Invalid property"); @@ -240,12 +249,12 @@ int luacon_elementwrite(lua_State* l) lua_rawget(l, 1); int i = lua_tointeger (l, lua_gettop(l)); lua_pop(l, 1); - if (!luacon_sim->IsElement(i)) + if (!sd.IsElement(i)) { return luaL_error(l, "Invalid index"); } - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[i]) + prop.Offset); + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[i]) + prop.Offset); LuaScriptInterface::LuaSetProperty(l, prop, propertyAddress, 3); luacon_model->BuildMenus(); @@ -278,21 +287,23 @@ String luacon_geterror() //tpt. api methods int luatpt_getelement(lua_State *l) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int t; if (lua_isnumber(l, 1)) { t = luaL_optint(l, 1, 1); - if (!luacon_sim->IsElementOrNone(t)) + if (!sd.IsElementOrNone(t)) { return luaL_error(l, "Unrecognised element number '%d'", t); } - tpt_lua_pushString(l, luacon_sim->elements[t].Name); + tpt_lua_pushString(l, elements[t].Name); } else { luaL_checktype(l, 1, LUA_TSTRING); auto name = tpt_lua_optByteString(l, 1, ""); - if ((t = luacon_sim->GetParticleType(name))==-1) + if ((t = sd.GetParticleType(name))==-1) return luaL_error(l, "Unrecognised element '%s'", name.c_str()); lua_pushinteger(l, t); } @@ -326,6 +337,7 @@ int luatpt_drawtext(lua_State* l) int luatpt_create(lua_State* l) { + auto &sd = SimulationData::CRef(); int x, y, retid, t = -1; x = abs(luaL_optint(l, 1, 0)); y = abs(luaL_optint(l, 2, 0)); @@ -334,13 +346,13 @@ int luatpt_create(lua_State* l) if (lua_isnumber(l, 3)) { t = luaL_optint(l, 3, 0); - if (!luacon_sim->IsElement(t)) + if (!sd.IsElement(t)) { return luaL_error(l, "Unrecognised element number '%d'", t); } } else { auto name = tpt_lua_optByteString(l, 3, "dust"); - if ((t = luacon_sim->GetParticleType(name)) == -1) + if ((t = sd.GetParticleType(name)) == -1) return luaL_error(l,"Unrecognised element '%s'", name.c_str()); } retid = luacon_sim->create_part(-1, x, y, t); @@ -547,6 +559,7 @@ int luatpt_reset_spark(lua_State* l) int luatpt_set_property(lua_State* l) { + auto &sd = SimulationData::CRef(); auto *luacon_ci = static_cast(commandInterface); int r, i, x, y, w, h, t = 0, nx, ny, partsel = 0; float f = 0; @@ -565,7 +578,7 @@ int luatpt_set_property(lua_State* l) if(!lua_isnumber(l, acount) && lua_isstring(l, acount)) { auto name = tpt_lua_optByteString(l, acount, "none"); - if ((partsel = luacon_sim->GetParticleType(name)) == -1) + if ((partsel = sd.GetParticleType(name)) == -1) return luaL_error(l, "Unrecognised element '%s'", name.c_str()); } } @@ -576,13 +589,13 @@ int luatpt_set_property(lua_State* l) else t = luaL_optint(l, 2, 0); - if (byteStringEqualsLiteral(prop, "type") && !luacon_sim->IsElementOrNone(t)) + if (byteStringEqualsLiteral(prop, "type") && !sd.IsElementOrNone(t)) return luaL_error(l, "Unrecognised element number '%d'", t); } else if (lua_isstring(l, 2)) { auto name = tpt_lua_checkByteString(l, 2); - if ((t = luacon_sim->GetParticleType(name))==-1) + if ((t = sd.GetParticleType(name))==-1) return luaL_error(l, "Unrecognised element '%s'", name.c_str()); } else @@ -1141,12 +1154,15 @@ int luatpt_menu_enabled(lua_State* l) int acount = lua_gettop(l); if (acount == 1) { - lua_pushboolean(l, luacon_sim->msections[menusection].doshow); + lua_pushboolean(l, SimulationData::CRef().msections[menusection].doshow); return 1; } luaL_checktype(l, 2, LUA_TBOOLEAN); int enabled = lua_toboolean(l, 2); - luacon_sim->msections[menusection].doshow = enabled; + { + auto &sd = SimulationData::Ref(); + sd.msections[menusection].doshow = enabled; + } luacon_model->BuildMenus(); return 0; } diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 3a884f946..d5625b6b7 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -451,11 +451,13 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): tptPart->Assign(l, -1); lua_pop(l, 1); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; lua_newtable(l); tptElements = lua_gettop(l); for (int i = 1; i < PT_NUM; i++) { - tpt_lua_pushString(l, luacon_sim->elements[i].Name.ToLower()); + tpt_lua_pushString(l, elements[i].Name.ToLower()); lua_newtable(l); currentElement = lua_gettop(l); lua_pushinteger(l, i); @@ -475,7 +477,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): tptElementTransitions = lua_gettop(l); for (int i = 1; i < PT_NUM; i++) { - tpt_lua_pushString(l, luacon_sim->elements[i].Name.ToLower()); + tpt_lua_pushString(l, elements[i].Name.ToLower()); lua_newtable(l); currentElement = lua_gettop(l); lua_newtable(l); @@ -536,14 +538,15 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): void LuaScriptInterface::custom_init_can_move() { - luacon_sim->init_can_move(); + auto &sd = SimulationData::Ref(); + sd.init_can_move(); for (auto moving = 0; moving < PT_NUM; ++moving) { for (auto into = 0; into < PT_NUM; ++into) { if (custom_can_move[moving][into] & 0x80) { - luacon_sim->can_move[moving][into] = custom_can_move[moving][into] & 0x7F; + sd.can_move[moving][into] = custom_can_move[moving][into] & 0x7F; } } } @@ -1112,6 +1115,8 @@ int simulation_deletesign(lua_State *l) void LuaScriptInterface::initSimulationAPI() { + auto &sd = SimulationData::CRef(); + //Methods struct luaL_Reg simulationAPIMethods [] = { {"partNeighbours", simulation_partNeighbours}, @@ -1227,7 +1232,7 @@ void LuaScriptInterface::initSimulationAPI() SETCONST(l, TOOL_NGRV); SETCONST(l, TOOL_MIX); SETCONST(l, TOOL_CYCL); - lua_pushinteger(l, luacon_sim->tools.size()); lua_setfield(l, -2, "TOOL_WIND"); + lua_pushinteger(l, sd.tools.size()); lua_setfield(l, -2, "TOOL_WIND"); SETCONST(l, DECO_DRAW); SETCONST(l, DECO_CLEAR); @@ -1266,12 +1271,12 @@ void LuaScriptInterface::initSimulationAPI() lua_newtable(l); for (int i = 0; i < UI_WALLCOUNT; i++) { - tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier); + tpt_lua_pushByteString(l, sd.wtypes[i].identifier); lua_pushinteger(l, i); lua_settable(l, -3); lua_pushinteger(l, i); - tpt_lua_pushByteString(l, luacon_sim->wtypes[i].identifier); + tpt_lua_pushByteString(l, sd.wtypes[i].identifier); lua_settable(l, -3); } lua_setfield(l, -2, "walls"); @@ -1898,6 +1903,7 @@ int LuaScriptInterface::simulation_floodWalls(lua_State * l) int LuaScriptInterface::simulation_toolBrush(lua_State * l) { + auto &sd = SimulationData::CRef(); int x = luaL_optint(l,1,-1); int y = luaL_optint(l,2,-1); int rx = luaL_optint(l,3,5); @@ -1905,12 +1911,12 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l) int tool = luaL_optint(l,5,0); int brushID = luaL_optint(l,6,CIRCLE_BRUSH); float strength = luaL_optnumber(l,7,1.0f); - if (tool == (int)luacon_sim->tools.size()) + if (tool == (int)sd.tools.size()) { lua_pushinteger(l, 0); return 1; } - else if (tool < 0 || tool > (int)luacon_sim->tools.size()) + else if (tool < 0 || tool > (int)sd.tools.size()) return luaL_error(l, "Invalid tool id '%d'", tool); Brush *brush = luacon_model->GetBrushByID(brushID); @@ -1926,6 +1932,7 @@ int LuaScriptInterface::simulation_toolBrush(lua_State * l) int LuaScriptInterface::simulation_toolLine(lua_State * l) { + auto &sd = SimulationData::CRef(); int x1 = luaL_optint(l,1,-1); int y1 = luaL_optint(l,2,-1); int x2 = luaL_optint(l,3,-1); @@ -1938,7 +1945,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l) if (x1 < 0 || x2 < 0 || x1 >= XRES || x2 >= XRES || y1 < 0 || y2 < 0 || y1 >= YRES || y2 >= YRES) return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2); - if (tool < 0 || tool >= (int)luacon_sim->tools.size()+1) + if (tool < 0 || tool >= (int)sd.tools.size()+1) return luaL_error(l, "Invalid tool id '%d'", tool); Brush *brush = luacon_model->GetBrushByID(brushID); @@ -1947,7 +1954,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l) auto newBrush = brush->Clone(); newBrush->SetRadius(ui::Point(rx, ry)); - if (tool == (int)luacon_sim->tools.size()) + if (tool == (int)sd.tools.size()) { Tool *windTool = luacon_model->GetToolFromIdentifier("DEFAULT_UI_WIND"); float oldStrength = windTool->Strength; @@ -1962,6 +1969,7 @@ int LuaScriptInterface::simulation_toolLine(lua_State * l) int LuaScriptInterface::simulation_toolBox(lua_State * l) { + auto &sd = SimulationData::CRef(); int x1 = luaL_optint(l,1,-1); int y1 = luaL_optint(l,2,-1); int x2 = luaL_optint(l,3,-1); @@ -1970,12 +1978,12 @@ int LuaScriptInterface::simulation_toolBox(lua_State * l) return luaL_error(l, "coordinates out of range (%d,%d),(%d,%d)", x1, y1, x2, y2); int tool = luaL_optint(l,5,0); float strength = luaL_optnumber(l,6,1.0f); - if (tool == (int)luacon_sim->tools.size()) + if (tool == (int)sd.tools.size()) { lua_pushinteger(l, 0); return 1; } - else if (tool < 0 || tool >= (int)luacon_sim->tools.size()) + else if (tool < 0 || tool >= (int)sd.tools.size()) return luaL_error(l, "Invalid tool id '%d'", tool); luacon_sim->ToolBox(x1, y1, x2, y2, tool, strength); @@ -2110,12 +2118,14 @@ int LuaScriptInterface::simulation_clearRect(lua_State * l) int LuaScriptInterface::simulation_resetTemp(lua_State * l) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; bool onlyConductors = luaL_optint(l, 1, 0); for (int i = 0; i < luacon_sim->parts_lastActiveIndex; i++) { - if (luacon_sim->parts[i].type && (luacon_sim->elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors)) + if (luacon_sim->parts[i].type && (elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors)) { - luacon_sim->parts[i].temp = luacon_sim->elements[luacon_sim->parts[i].type].DefaultProperties.temp; + luacon_sim->parts[i].temp = elements[luacon_sim->parts[i].type].DefaultProperties.temp; } } return 0; @@ -2427,14 +2437,16 @@ int LuaScriptInterface::simulation_canMove(lua_State * l) if (lua_gettop(l) < 3) { - lua_pushnumber(l, luacon_sim->can_move[movingElement][destinationElement]); + auto &sd = SimulationData::CRef(); + lua_pushnumber(l, sd.can_move[movingElement][destinationElement]); return 1; } else { int setting = luaL_checkint(l, 3) & 0x7F; luacon_ci->custom_can_move[movingElement][destinationElement] = setting | 0x80; - luacon_sim->can_move[movingElement][destinationElement] = setting; + auto &sd = SimulationData::Ref(); + sd.can_move[movingElement][destinationElement] = setting; return 0; } } @@ -2684,9 +2696,10 @@ int LuaScriptInterface::simulation_replaceModeFlags(lua_State *l) int LuaScriptInterface::simulation_listCustomGol(lua_State *l) { + auto &sd = SimulationData::CRef(); int i = 0; lua_newtable(l); - for (auto &cgol : luacon_sim->GetCustomGol()) + for (auto &cgol : sd.GetCustomGol()) { lua_newtable(l); tpt_lua_pushString(l, cgol.nameString); @@ -2706,6 +2719,7 @@ int LuaScriptInterface::simulation_listCustomGol(lua_State *l) int LuaScriptInterface::simulation_addCustomGol(lua_State *l) { + auto &sd = SimulationData::CRef(); int rule; String ruleString; if (lua_isnumber(l, 1)) @@ -2727,7 +2741,7 @@ int LuaScriptInterface::simulation_addCustomGol(lua_State *l) return luaL_error(l, "Invalid name provided"); if (rule == -1) return luaL_error(l, "Invalid rule provided"); - if (luacon_sim->GetCustomGOLByRule(rule)) + if (sd.GetCustomGOLByRule(rule)) return luaL_error(l, "This Custom GoL rule already exists"); if (!AddCustomGol(ruleString, nameString, color1, color2)) @@ -3145,15 +3159,17 @@ void LuaScriptInterface::initElementsAPI() SETCONST(l, SC_DECO); //Element identifiers + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for(int i = 0; i < PT_NUM; i++) { - if(luacon_sim->elements[i].Enabled) + if(elements[i].Enabled) { - tpt_lua_pushByteString(l, luacon_sim->elements[i].Identifier); + tpt_lua_pushByteString(l, elements[i].Identifier); lua_pushinteger(l, i); lua_settable(l, -3); - ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", luacon_sim->elements[i].Name.ToUtf8()); - if (i != 0 && i != PT_NBHL && i != PT_NWHL && luacon_sim->elements[i].Identifier != realIdentifier) + ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", elements[i].Name.ToUtf8()); + if (i != 0 && i != PT_NBHL && i != PT_NWHL && elements[i].Identifier != realIdentifier) { tpt_lua_pushByteString(l, realIdentifier); lua_pushinteger(l, i); @@ -3270,52 +3286,64 @@ void LuaScriptInterface::LuaSetParticleProperty(lua_State* l, int particleID, St int LuaScriptInterface::elements_loadDefault(lua_State * l) { + auto &builtinElements = GetElements(); auto *luacon_ci = static_cast(commandInterface); - int args = lua_gettop(l); - if (args) { - luaL_checktype(l, 1, LUA_TNUMBER); - int id = lua_tointeger(l, 1); - if (id < 0 || id >= PT_NUM) - return luaL_error(l, "Invalid element"); - - lua_getglobal(l, "elements"); - tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier); - lua_pushnil(l); - lua_settable(l, -3); - - auto const &elementList = GetElements(); - if (id < (int)elementList.size()) - luacon_sim->elements[id] = elementList[id]; - else - luacon_sim->elements[id] = Element(); - - tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier); - lua_pushinteger(l, id); - lua_settable(l, -3); - lua_pop(l, 1); - } - else - { - auto const &elementList = GetElements(); - for (int i = 0; i < PT_NUM; i++) + int args = lua_gettop(l); + if (args) { - if (i < (int)elementList.size()) - luacon_sim->elements[i] = elementList[i]; - else - luacon_sim->elements[i] = Element(); + luaL_checktype(l, 1, LUA_TNUMBER); + int id = lua_tointeger(l, 1); + if (id < 0 || id >= PT_NUM) + return luaL_error(l, "Invalid element"); + + lua_getglobal(l, "elements"); + ByteString identifier = SimulationData::CRef().elements[id].Identifier; + tpt_lua_pushByteString(l, identifier); + lua_pushnil(l); + lua_settable(l, -3); + + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + if (id < (int)builtinElements.size()) + elements[id] = builtinElements[id]; + else + elements[id] = Element(); + } + + tpt_lua_pushByteString(l, identifier); + lua_pushinteger(l, id); + lua_settable(l, -3); + lua_pop(l, 1); } - lua_pushnil(l); - lua_setglobal(l, "elements"); - lua_pushnil(l); - lua_setglobal(l, "elem"); + else + { + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + for (int i = 0; i < PT_NUM; i++) + { + if (i < (int)builtinElements.size()) + elements[i] = builtinElements[i]; + else + elements[i] = Element(); + } + } + lua_pushnil(l); + lua_setglobal(l, "elements"); + lua_pushnil(l); + lua_setglobal(l, "elem"); - lua_getglobal(l, "package"); - lua_getfield(l, -1, "loaded"); - lua_pushnil(l); - lua_setfield(l, -2, "elements"); + lua_getglobal(l, "package"); + lua_getfield(l, -1, "loaded"); + lua_pushnil(l); + lua_setfield(l, -2, "elements"); - luacon_ci->initElementsAPI(); + luacon_ci->initElementsAPI(); + } } luacon_model->BuildMenus(); @@ -3355,40 +3383,49 @@ int LuaScriptInterface::elements_allocate(lua_State * l) auto identifier = group + "_PT_" + id; - for(int i = 0; i < PT_NUM; i++) - { - if(luacon_sim->elements[i].Enabled && ByteString(luacon_sim->elements[i].Identifier) == identifier) - return luaL_error(l, "Element identifier already in use"); - } - int newID = -1; - // Start out at 255 so that lua element IDs are still one byte (better save compatibility) - for (int i = PT_NUM >= 255 ? 255 : PT_NUM; i >= 0; i--) { - if (!luacon_sim->elements[i].Enabled) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + for(int i = 0; i < PT_NUM; i++) { - newID = i; - break; + if(elements[i].Enabled && ByteString(elements[i].Identifier) == identifier) + return luaL_error(l, "Element identifier already in use"); } - } - // If not enough space, then we start with the new maimum ID - if (newID == -1) - { - for (int i = PT_NUM-1; i >= 255; i--) + + // Start out at 255 so that lua element IDs are still one byte (better save compatibility) + for (int i = PT_NUM >= 255 ? 255 : PT_NUM; i >= 0; i--) { - if (!luacon_sim->elements[i].Enabled) + if (!elements[i].Enabled) { newID = i; break; } } + // If not enough space, then we start with the new maimum ID + if (newID == -1) + { + for (int i = PT_NUM-1; i >= 255; i--) + { + if (!elements[i].Enabled) + { + newID = i; + break; + } + } + } } if (newID != -1) { - luacon_sim->elements[newID] = Element(); - luacon_sim->elements[newID].Enabled = true; - luacon_sim->elements[newID].Identifier = identifier; + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + elements[newID] = Element(); + elements[newID].Enabled = true; + elements[newID].Identifier = identifier; + } lua_getglobal(l, "elements"); tpt_lua_pushByteString(l, identifier); @@ -3412,7 +3449,8 @@ int LuaScriptInterface::elements_allocate(lua_State * l) static int luaUpdateWrapper(UPDATE_FUNC_ARGS) { auto *luacon_ci = static_cast(commandInterface); - auto *builtinUpdate = GetElements()[parts[i].type].Update; + auto &builtinElements = GetElements(); + auto *builtinUpdate = builtinElements[parts[i].type].Update; if (builtinUpdate && lua_el_mode[parts[i].type] == 1) { if (builtinUpdate(UPDATE_FUNC_SUBCALL_ARGS)) @@ -3591,109 +3629,115 @@ static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS) int LuaScriptInterface::elements_element(lua_State * l) { + auto &builtinElements = GetElements(); auto *luacon_ci = static_cast(commandInterface); int id = luaL_checkinteger(l, 1); - if (!luacon_sim->IsElementOrNone(id)) + if (!SimulationData::CRef().IsElementOrNone(id)) { return luaL_error(l, "Invalid element"); } if (lua_gettop(l) > 1) { - luaL_checktype(l, 2, LUA_TTABLE); - //Write values from native data to a table - for (auto &prop : Element::GetProperties()) { - tpt_lua_pushByteString(l, prop.Name); - lua_gettable(l, -2); - if (lua_type(l, -1) != LUA_TNIL) + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + luaL_checktype(l, 2, LUA_TTABLE); + //Write values from native data to a table + for (auto &prop : Element::GetProperties()) { - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop.Offset); - LuaSetProperty(l, prop, propertyAddress, -1); + tpt_lua_pushByteString(l, prop.Name); + lua_gettable(l, -2); + if (lua_type(l, -1) != LUA_TNIL) + { + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop.Offset); + LuaSetProperty(l, prop, propertyAddress, -1); + } + lua_pop(l, 1); + } + + lua_getfield(l, -1, "Update"); + if (lua_type(l, -1) == LUA_TFUNCTION) + { + lua_el_func[id].Assign(l, -1); + lua_el_mode[id] = 1; + elements[id].Update = luaUpdateWrapper; + } + else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) + { + lua_el_func[id].Clear(); + lua_el_mode[id] = 0; + elements[id].Update = builtinElements[id].Update; + } + lua_pop(l, 1); + + lua_getfield(l, -1, "Graphics"); + if (lua_type(l, -1) == LUA_TFUNCTION) + { + lua_gr_func[id].Assign(l, -1); + elements[id].Graphics = luaGraphicsWrapper; + } + else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) + { + lua_gr_func[id].Clear(); + elements[id].Graphics = builtinElements[id].Graphics; + } + lua_pop(l, 1); + + lua_getfield(l, -1, "Create"); + if (lua_type(l, -1) == LUA_TFUNCTION) + { + luaCreateHandlers[id].Assign(l, -1); + elements[id].Create = luaCreateWrapper; + } + else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) + { + luaCreateHandlers[id].Clear(); + elements[id].Create = builtinElements[id].Create; + } + lua_pop(l, 1); + + lua_getfield(l, -1, "CreateAllowed"); + if (lua_type(l, -1) == LUA_TFUNCTION) + { + luaCreateAllowedHandlers[id].Assign(l, -1); + elements[id].CreateAllowed = luaCreateAllowedWrapper; + } + else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) + { + luaCreateAllowedHandlers[id].Clear(); + elements[id].CreateAllowed = builtinElements[id].CreateAllowed; + } + lua_pop(l, 1); + + lua_getfield(l, -1, "ChangeType"); + if (lua_type(l, -1) == LUA_TFUNCTION) + { + luaChangeTypeHandlers[id].Assign(l, -1); + elements[id].ChangeType = luaChangeTypeWrapper; + } + else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) + { + luaChangeTypeHandlers[id].Clear(); + elements[id].ChangeType = builtinElements[id].ChangeType; + } + lua_pop(l, 1); + + lua_getfield(l, -1, "CtypeDraw"); + if (lua_type(l, -1) == LUA_TFUNCTION) + { + luaCtypeDrawHandlers[id].Assign(l, -1); + elements[id].CtypeDraw = luaCtypeDrawWrapper; + } + else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) + { + luaCtypeDrawHandlers[id].Clear(); + elements[id].CtypeDraw = builtinElements[id].CtypeDraw; } lua_pop(l, 1); } - lua_getfield(l, -1, "Update"); - if (lua_type(l, -1) == LUA_TFUNCTION) - { - lua_el_func[id].Assign(l, -1); - lua_el_mode[id] = 1; - luacon_sim->elements[id].Update = luaUpdateWrapper; - } - else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) - { - lua_el_func[id].Clear(); - lua_el_mode[id] = 0; - luacon_sim->elements[id].Update = GetElements()[id].Update; - } - lua_pop(l, 1); - - lua_getfield(l, -1, "Graphics"); - if (lua_type(l, -1) == LUA_TFUNCTION) - { - lua_gr_func[id].Assign(l, -1); - luacon_sim->elements[id].Graphics = luaGraphicsWrapper; - } - else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) - { - lua_gr_func[id].Clear(); - luacon_sim->elements[id].Graphics = GetElements()[id].Graphics; - } - lua_pop(l, 1); - - lua_getfield(l, -1, "Create"); - if (lua_type(l, -1) == LUA_TFUNCTION) - { - luaCreateHandlers[id].Assign(l, -1); - luacon_sim->elements[id].Create = luaCreateWrapper; - } - else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) - { - luaCreateHandlers[id].Clear(); - luacon_sim->elements[id].Create = GetElements()[id].Create; - } - lua_pop(l, 1); - - lua_getfield(l, -1, "CreateAllowed"); - if (lua_type(l, -1) == LUA_TFUNCTION) - { - luaCreateAllowedHandlers[id].Assign(l, -1); - luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper; - } - else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) - { - luaCreateAllowedHandlers[id].Clear(); - luacon_sim->elements[id].CreateAllowed = GetElements()[id].CreateAllowed; - } - lua_pop(l, 1); - - lua_getfield(l, -1, "ChangeType"); - if (lua_type(l, -1) == LUA_TFUNCTION) - { - luaChangeTypeHandlers[id].Assign(l, -1); - luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper; - } - else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) - { - luaChangeTypeHandlers[id].Clear(); - luacon_sim->elements[id].ChangeType = GetElements()[id].ChangeType; - } - lua_pop(l, 1); - - lua_getfield(l, -1, "CtypeDraw"); - if (lua_type(l, -1) == LUA_TFUNCTION) - { - luaCtypeDrawHandlers[id].Assign(l, -1); - luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper; - } - else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1)) - { - luaCtypeDrawHandlers[id].Clear(); - luacon_sim->elements[id].CtypeDraw = GetElements()[id].CtypeDraw; - } - lua_pop(l, 1); - lua_getfield(l, -1, "DefaultProperties"); SetDefaultProperties(l, id, lua_gettop(l)); lua_pop(l, 1); @@ -3707,17 +3751,19 @@ int LuaScriptInterface::elements_element(lua_State * l) } else { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; //Write values from native data to a table lua_newtable(l); for (auto &prop : Element::GetProperties()) { tpt_lua_pushByteString(l, prop.Name); - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop.Offset); + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop.Offset); LuaGetProperty(l, prop, propertyAddress); lua_settable(l, -3); } - tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier); + tpt_lua_pushByteString(l, elements[id].Identifier); lua_setfield(l, -2, "Identifier"); GetDefaultProperties(l, id); @@ -3729,10 +3775,12 @@ int LuaScriptInterface::elements_element(lua_State * l) void LuaScriptInterface::GetDefaultProperties(lua_State * l, int id) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; lua_newtable(l); for (auto &prop : Particle::GetProperties()) { - auto propertyAddress = reinterpret_cast((reinterpret_cast(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset); + auto propertyAddress = reinterpret_cast((reinterpret_cast(&elements[id].DefaultProperties)) + prop.Offset); tpt_lua_pushByteString(l, prop.Name); LuaGetProperty(l, prop, propertyAddress); lua_settable(l, -3); @@ -3748,6 +3796,8 @@ void LuaScriptInterface::GetDefaultProperties(lua_State * l, int id) void LuaScriptInterface::SetDefaultProperties(lua_State * l, int id, int stackPos) { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, stackPos) == LUA_TTABLE) { for (auto &prop : Particle::GetProperties()) @@ -3768,7 +3818,7 @@ void LuaScriptInterface::SetDefaultProperties(lua_State * l, int id, int stackPo } if (lua_type(l, -1) != LUA_TNIL) { - auto propertyAddress = reinterpret_cast((reinterpret_cast(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset); + auto propertyAddress = reinterpret_cast((reinterpret_cast(&elements[id].DefaultProperties)) + prop.Offset); LuaSetProperty(l, prop, propertyAddress, -1); } lua_pop(l, 1); @@ -3778,9 +3828,10 @@ void LuaScriptInterface::SetDefaultProperties(lua_State * l, int id, int stackPo int LuaScriptInterface::elements_property(lua_State * l) { + auto &builtinElements = GetElements(); auto *luacon_ci = static_cast(commandInterface); int id = luaL_checkinteger(l, 1); - if (!luacon_sim->IsElementOrNone(id)) + if (!SimulationData::CRef().IsElementOrNone(id)) { return luaL_error(l, "Invalid element"); } @@ -3800,14 +3851,18 @@ int LuaScriptInterface::elements_property(lua_State * l) if (prop->Type == StructProperty::TransitionType) { int type = luaL_checkinteger(l, 3); - if (!luacon_sim->IsElementOrNone(type) && type != NT && type != ST) + if (!SimulationData::CRef().IsElementOrNone(type) && type != NT && type != ST) { return luaL_error(l, "Invalid element"); } } - - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop->Offset); - LuaSetProperty(l, *prop, propertyAddress, 3); + { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset); + LuaSetProperty(l, *prop, propertyAddress, 3); + } } luacon_model->BuildMenus(); @@ -3817,6 +3872,8 @@ int LuaScriptInterface::elements_property(lua_State * l) } else if (propertyName == "Update") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { switch (luaL_optint(l, 4, 0)) @@ -3834,80 +3891,90 @@ int LuaScriptInterface::elements_property(lua_State * l) break; } lua_el_func[id].Assign(l, 3); - luacon_sim->elements[id].Update = luaUpdateWrapper; + elements[id].Update = luaUpdateWrapper; } else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) { lua_el_func[id].Clear(); lua_el_mode[id] = 0; - luacon_sim->elements[id].Update = GetElements()[id].Update; + elements[id].Update = builtinElements[id].Update; } } else if (propertyName == "Graphics") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { lua_gr_func[id].Assign(l, 3); - luacon_sim->elements[id].Graphics = luaGraphicsWrapper; + elements[id].Graphics = luaGraphicsWrapper; } else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) { lua_gr_func[id].Clear(); - luacon_sim->elements[id].Graphics = GetElements()[id].Graphics; + elements[id].Graphics = builtinElements[id].Graphics; } luacon_ren->graphicscache[id].isready = 0; SaveRenderer::Ref().Flush(id, id + 1); } else if (propertyName == "Create") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaCreateHandlers[id].Assign(l, 3); - luacon_sim->elements[id].Create = luaCreateWrapper; + elements[id].Create = luaCreateWrapper; } else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) { luaCreateHandlers[id].Clear(); - luacon_sim->elements[id].Create = GetElements()[id].Create; + elements[id].Create = builtinElements[id].Create; } } else if (propertyName == "CreateAllowed") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaCreateAllowedHandlers[id].Assign(l, 3); - luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper; + elements[id].CreateAllowed = luaCreateAllowedWrapper; } else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) { luaCreateAllowedHandlers[id].Clear(); - luacon_sim->elements[id].CreateAllowed = GetElements()[id].CreateAllowed; + elements[id].CreateAllowed = builtinElements[id].CreateAllowed; } } else if (propertyName == "ChangeType") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaChangeTypeHandlers[id].Assign(l, 3); - luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper; + elements[id].ChangeType = luaChangeTypeWrapper; } else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) { luaChangeTypeHandlers[id].Clear(); - luacon_sim->elements[id].ChangeType = GetElements()[id].ChangeType; + elements[id].ChangeType = builtinElements[id].ChangeType; } } else if (propertyName == "CtypeDraw") { + auto &sd = SimulationData::Ref(); + auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaCtypeDrawHandlers[id].Assign(l, 3); - luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper; + elements[id].CtypeDraw = luaCtypeDrawWrapper; } else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3)) { luaCtypeDrawHandlers[id].Clear(); - luacon_sim->elements[id].CtypeDraw = GetElements()[id].CtypeDraw; + elements[id].CtypeDraw = builtinElements[id].CtypeDraw; } } else if (propertyName == "DefaultProperties") @@ -3922,15 +3989,17 @@ int LuaScriptInterface::elements_property(lua_State * l) } else { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (prop != properties.end()) { - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop->Offset); + intptr_t propertyAddress = (intptr_t)(((const unsigned char*)&elements[id]) + prop->Offset); LuaGetProperty(l, *prop, propertyAddress); return 1; } else if (propertyName == "Identifier") { - tpt_lua_pushByteString(l, luacon_sim->elements[id].Identifier); + tpt_lua_pushByteString(l, elements[id].Identifier); return 1; } else if (propertyName == "DefaultProperties") @@ -3948,18 +4017,26 @@ int LuaScriptInterface::elements_property(lua_State * l) int LuaScriptInterface::elements_free(lua_State * l) { int id = luaL_checkinteger(l, 1); - if (!luacon_sim->IsElement(id)) + ByteString identifier; { - return luaL_error(l, "Invalid element"); + auto &sd = SimulationData::CRef(); + if (!sd.IsElement(id)) + { + return luaL_error(l, "Invalid element"); + } + + identifier = sd.elements[id].Identifier; + if (identifier.BeginsWith("DEFAULT_PT_")) + { + return luaL_error(l, "Cannot free default elements"); + } } - ByteString identifier = luacon_sim->elements[id].Identifier; - if (identifier.BeginsWith("DEFAULT_PT_")) { - return luaL_error(l, "Cannot free default elements"); + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + sd.elements[id].Enabled = false; } - - luacon_sim->elements[id].Enabled = false; luacon_model->BuildMenus(); lua_getglobal(l, "elements"); @@ -3973,7 +4050,8 @@ int LuaScriptInterface::elements_free(lua_State * l) int LuaScriptInterface::elements_exists(lua_State * l) { - lua_pushboolean(l, luacon_sim->IsElement(luaL_checkinteger(l, 1))); + auto &sd = SimulationData::CRef(); + lua_pushboolean(l, sd.IsElement(luaL_checkinteger(l, 1))); return 1; } diff --git a/src/lua/TPTScriptInterface.cpp b/src/lua/TPTScriptInterface.cpp index 659715f17..b03995292 100644 --- a/src/lua/TPTScriptInterface.cpp +++ b/src/lua/TPTScriptInterface.cpp @@ -244,6 +244,7 @@ String TPTScriptInterface::FormatCommand(String command) AnyType TPTScriptInterface::tptS_set(std::deque * words) { + auto &sd = SimulationData::CRef(); //Arguments from stack StringType property = eval(words); AnyType selector = eval(words); @@ -300,7 +301,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque * words) } else { - newValue = m->GetSimulation()->GetParticleType(((StringType)value).Value().ToUtf8()); + newValue = sd.GetParticleType(((StringType)value).Value().ToUtf8()); if (newValue < 0 || newValue >= PT_NUM) { // TODO: add element CAKE to invalidate this @@ -312,7 +313,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque * words) } else throw GeneralException("Invalid value for assignment"); - if (property.Value() == "type" && (newValue < 0 || newValue >= PT_NUM || !sim->elements[newValue].Enabled)) + if (property.Value() == "type" && (newValue < 0 || newValue >= PT_NUM || !sd.elements[newValue].Enabled)) throw GeneralException("Invalid element"); if (selector.GetType() == TypePoint || selector.GetType() == TypeNumber) @@ -390,7 +391,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque * words) if (selector.GetType() == TypeNumber) type = ((NumberType)selector).Value(); else if (selector.GetType() == TypeString) - type = m->GetSimulation()->GetParticleType(((StringType)selector).Value().ToUtf8()); + type = sd.GetParticleType(((StringType)selector).Value().ToUtf8()); if (type<0 || type>=PT_NUM) throw GeneralException("Invalid particle type"); @@ -439,6 +440,7 @@ AnyType TPTScriptInterface::tptS_set(std::deque * words) AnyType TPTScriptInterface::tptS_create(std::deque * words) { + auto &sd = SimulationData::CRef(); //Arguments from stack AnyType createType = eval(words); PointType position = eval(words); @@ -449,7 +451,7 @@ AnyType TPTScriptInterface::tptS_create(std::deque * words) if(createType.GetType() == TypeNumber) type = ((NumberType)createType).Value(); else if(createType.GetType() == TypeString) - type = m->GetSimulation()->GetParticleType(((StringType)createType).Value().ToUtf8()); + type = sd.GetParticleType(((StringType)createType).Value().ToUtf8()); else throw GeneralException("Invalid type"); @@ -549,6 +551,7 @@ AnyType TPTScriptInterface::tptS_bubble(std::deque * words) AnyType TPTScriptInterface::tptS_reset(std::deque * words) { + auto &sd = SimulationData::CRef(); //Arguments from stack StringType reset = eval(words); String resetStr = reset.Value(); @@ -582,7 +585,7 @@ AnyType TPTScriptInterface::tptS_reset(std::deque * words) { if (sim->parts[i].type) { - sim->parts[i].temp = sim->elements[sim->parts[i].type].DefaultProperties.temp; + sim->parts[i].temp = sd.elements[sim->parts[i].type].DefaultProperties.temp; } } } diff --git a/src/simulation/Air.cpp b/src/simulation/Air.cpp index 166ea561e..4d7aaef50 100644 --- a/src/simulation/Air.cpp +++ b/src/simulation/Air.cpp @@ -354,6 +354,8 @@ void Air::Invert() // called when loading saves / stamps to ensure nothing "leaks" the first frame void Air::ApproximateBlockAirMaps() { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (int i = 0; i <= sim.parts_lastActiveIndex; i++) { int type = sim.parts[i].type; @@ -372,7 +374,7 @@ void Air::ApproximateBlockAirMaps() } } // mostly accurate insulator blocking, besides checking GEL - else if ((type == PT_HSWC && sim.parts[i].life != 10) || sim.elements[type].HeatConduct <= (sim.rng()%250)) + else if ((type == PT_HSWC && sim.parts[i].life != 10) || elements[type].HeatConduct <= (sim.rng()%250)) { int x = ((int)(sim.parts[i].x+0.5f))/CELL, y = ((int)(sim.parts[i].y+0.5f))/CELL; if (InBounds(x, y) && !(bmap_blockairh[y][x]&0x8)) diff --git a/src/simulation/BuiltinGOL.h b/src/simulation/BuiltinGOL.h index 9a4f7c959..bf7417d96 100644 --- a/src/simulation/BuiltinGOL.h +++ b/src/simulation/BuiltinGOL.h @@ -8,7 +8,8 @@ struct BuiltinGOL String name; int oldtype; int ruleset; - RGB colour, colour2; + RGB colour = RGB(0, 0, 0); + RGB colour2 = RGB(0, 0, 0); int goltype; String description; }; diff --git a/src/simulation/Editing.cpp b/src/simulation/Editing.cpp index 2c38765e0..1cbd316f6 100644 --- a/src/simulation/Editing.cpp +++ b/src/simulation/Editing.cpp @@ -13,7 +13,7 @@ #include #include -std::unique_ptr Simulation::CreateSnapshot() +std::unique_ptr Simulation::CreateSnapshot() const { auto snap = std::make_unique(); snap->AirPressure .insert (snap->AirPressure .begin(), &pv [0][0] , &pv [0][0] + NCELL); @@ -188,7 +188,8 @@ int Simulation::Tool(int x, int y, int tool, int brushX, int brushY, float stren cpart = &(parts[ID(r)]); else if ((r = photons[y][x])) cpart = &(parts[ID(r)]); - return tools[tool].Perform(this, cpart, x, y, brushX, brushY, strength); + auto &sd = SimulationData::CRef(); + return sd.tools[tool].Perform(this, cpart, x, y, brushX, brushY, strength); } int Simulation::CreateWalls(int x, int y, int rx, int ry, int wall, Brush const *cBrush) @@ -428,27 +429,6 @@ int Simulation::CreatePartFlags(int x, int y, int c, int flags) return 0; } -int Simulation::GetParticleType(ByteString type) -{ - type = type.ToUpper(); - - // alternative names for some elements - if (byteStringEqualsLiteral(type, "C4")) - return PT_PLEX; - else if (byteStringEqualsLiteral(type, "C5")) - return PT_C5; - else if (byteStringEqualsLiteral(type, "NONE")) - return PT_NONE; - for (int i = 1; i < PT_NUM; i++) - { - if (elements[i].Name.size() && elements[i].Enabled && type == elements[i].Name.ToUtf8().ToUpper()) - { - return i; - } - } - return -1; -} - void Simulation::ApplyDecoration(int x, int y, int colR_, int colG_, int colB_, int colA_, int mode) { int rp; @@ -1058,6 +1038,8 @@ int Simulation::FloodParts(int x, int y, int fullc, int cm, int flags) coord_stack[coord_stack_size][1] = y; coord_stack_size++; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; do { coord_stack_size--; diff --git a/src/simulation/Element.cpp b/src/simulation/Element.cpp index 2ca1b3b22..fb5d67faa 100644 --- a/src/simulation/Element.cpp +++ b/src/simulation/Element.cpp @@ -216,14 +216,16 @@ int Element::legacyUpdate(UPDATE_FUNC_ARGS) { int Element::defaultGraphics(GRAPHICS_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int t = cpart->type; //Property based defaults - if(ren->sim->elements[t].Properties & PROP_RADIOACTIVE) *pixel_mode |= PMODE_GLOW; - if(ren->sim->elements[t].Properties & TYPE_LIQUID) + if(elements[t].Properties & PROP_RADIOACTIVE) *pixel_mode |= PMODE_GLOW; + if(elements[t].Properties & TYPE_LIQUID) { *pixel_mode |= PMODE_BLUR; } - if(ren->sim->elements[t].Properties & TYPE_GAS) + if(elements[t].Properties & TYPE_GAS) { *pixel_mode &= ~PMODE; *pixel_mode |= FIRE_BLEND; @@ -238,7 +240,9 @@ int Element::defaultGraphics(GRAPHICS_FUNC_ARGS) bool Element::basicCtypeDraw(CTYPEDRAW_FUNC_ARGS) { - if (sim->parts[i].type == t || sim->elements[t].Properties & PROP_NOCTYPEDRAW) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (sim->parts[i].type == t || elements[t].Properties & PROP_NOCTYPEDRAW) { return false; } diff --git a/src/simulation/ElementClasses.cpp b/src/simulation/ElementClasses.cpp index 74ed3bbee..2dc7ae7b6 100644 --- a/src/simulation/ElementClasses.cpp +++ b/src/simulation/ElementClasses.cpp @@ -1,12 +1,12 @@ #include "ElementCommon.h" -std::vector const &GetElements() +std::array const &GetElements() { struct DoOnce { - std::vector elements; + std::array elements; - DoOnce() : elements(PT_NUM) + DoOnce() { #define ELEMENT_NUMBERS_CALL #include "ElementNumbers.h" diff --git a/src/simulation/ElementClasses.h b/src/simulation/ElementClasses.h index eae598970..a6f9a7100 100644 --- a/src/simulation/ElementClasses.h +++ b/src/simulation/ElementClasses.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "SimulationData.h" #include "Element.h" @@ -8,4 +8,4 @@ #include "ElementNumbers.h" #undef ELEMENT_NUMBERS_ENUMERATE -std::vector const &GetElements(); +std::array const &GetElements(); diff --git a/src/simulation/ElementCommon.h b/src/simulation/ElementCommon.h index 3f6f90c74..6aa2a8c8c 100644 --- a/src/simulation/ElementCommon.h +++ b/src/simulation/ElementCommon.h @@ -8,6 +8,7 @@ #include "Particle.h" #include "ElementGraphics.h" #include "Simulation.h" +#include "SimulationData.h" #include "graphics/Renderer.h" #include #include diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index ad6709dae..63dea381d 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -6,6 +6,7 @@ #include "graphics/Renderer.h" #include "Simulation.h" +#include "SimulationData.h" SaveRenderer::SaveRenderer(){ sim = new Simulation(); @@ -22,6 +23,9 @@ void SaveRenderer::Flush(int begin, int end) std::pair, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) { + // this function usually runs on a thread different from where element info in SimulationData may be written, so we acquire a read-only lock on it + auto &sd = SimulationData::CRef(); + std::shared_lock lk(sd.elementGraphicsMx); std::lock_guard gx(renderMutex); ren->ResetModes(); diff --git a/src/simulation/Sign.cpp b/src/simulation/Sign.cpp index e885fcc65..590bd21ff 100644 --- a/src/simulation/Sign.cpp +++ b/src/simulation/Sign.cpp @@ -1,7 +1,8 @@ #include "Sign.h" #include "graphics/Graphics.h" -#include "simulation/Simulation.h" +#include "Simulation.h" +#include "SimulationData.h" sign::sign(String text_, int x_, int y_, Justification justification_): x(x_), @@ -13,6 +14,7 @@ sign::sign(String text_, int x_, int y_, Justification justification_): String sign::getDisplayText(Simulation *sim, int &x0, int &y0, int &w, int &h, bool colorize, bool *v95) const { + auto &sd = SimulationData::CRef(); String drawable_text; auto si = std::make_pair(0, Type::Normal); if (text.find('{') == text.npos) @@ -79,13 +81,13 @@ String sign::getDisplayText(Simulation *sim, int &x0, int &y0, int &w, int &h, b } else if (between_curlies == "type") { - formatted_text << (part ? sim->BasicParticleInfo(*part) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); + formatted_text << (part ? sd.BasicParticleInfo(*part) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); if (v95) *v95 = true; } else if (between_curlies == "ctype") { - formatted_text << (part ? (sim->IsElementOrNone(part->ctype) ? sim->ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); + formatted_text << (part ? (sd.IsElementOrNone(part->ctype) ? sd.ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); if (v95) *v95 = true; } diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 74a0fa132..dab7bbd2e 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -4,7 +4,6 @@ #include "gravity/Gravity.h" #include "ToolClasses.h" #include "SimulationData.h" -#include "GOLString.h" #include "client/GameSave.h" #include "common/tpt-compat.h" #include "common/tpt-rand.h" @@ -30,6 +29,9 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec { partMap[i] = i; } + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if(save->palette.size()) { for(int i = 0; i < PT_NUM; i++) @@ -359,6 +361,9 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR // Now stores all particles, not just SOAP (but still only used for soap) std::map particleMap; std::set paletteSet; + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (int i = 0; i < NPART; i++) { int x, y; @@ -493,8 +498,10 @@ void Simulation::SaveSimOptions(GameSave &gameSave) gameSave.aheatEnable = aheat_enable; } -bool Simulation::FloodFillPmapCheck(int x, int y, int type) +bool Simulation::FloodFillPmapCheck(int x, int y, int type) const { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (type == 0) return !pmap[y][x] && !photons[y][x]; if (elements[type].Properties&TYPE_ENERGY) @@ -711,6 +718,8 @@ bool Simulation::flood_water(int x, int y, int i) char *bitmap = bitmapPtr.get(); std::fill(&bitmap[0], &bitmap[0] + XRES * YRES, 0); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; try { CoordStack& cs = getCoordStackSingleton(); @@ -1101,6 +1110,8 @@ void Simulation::clear_sim(void) bool Simulation::IsWallBlocking(int x, int y, int type) const { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (bmap[y/CELL][x/CELL]) { int wall = bmap[y/CELL][x/CELL]; @@ -1122,145 +1133,6 @@ bool Simulation::IsWallBlocking(int x, int y, int type) const return false; } -void Simulation::init_can_move() -{ - int movingType, destinationType; - // can_move[moving type][type at destination] - // 0 = No move/Bounce - // 1 = Swap - // 2 = Both particles occupy the same space. - // 3 = Varies, go run some extra checks - - //particles that don't exist shouldn't move... - for (destinationType = 0; destinationType < PT_NUM; destinationType++) - can_move[0][destinationType] = 0; - - //initialize everything else to swapping by default - for (movingType = 1; movingType < PT_NUM; movingType++) - for (destinationType = 0; destinationType < PT_NUM; destinationType++) - can_move[movingType][destinationType] = 1; - - //photons go through everything by default - for (destinationType = 1; destinationType < PT_NUM; destinationType++) - can_move[PT_PHOT][destinationType] = 2; - - for (movingType = 1; movingType < PT_NUM; movingType++) - { - for (destinationType = 1; destinationType < PT_NUM; destinationType++) - { - //weight check, also prevents particles of same type displacing each other - if (elements[movingType].Weight <= elements[destinationType].Weight || destinationType == PT_GEL) - can_move[movingType][destinationType] = 0; - - //other checks for NEUT and energy particles - if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTPASS)) - can_move[movingType][destinationType] = 2; - if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTABSORB)) - can_move[movingType][destinationType] = 1; - if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTPENETRATE)) - can_move[movingType][destinationType] = 1; - if (destinationType == PT_NEUT && (elements[movingType].Properties&PROP_NEUTPENETRATE)) - can_move[movingType][destinationType] = 0; - if ((elements[movingType].Properties&TYPE_ENERGY) && (elements[destinationType].Properties&TYPE_ENERGY)) - can_move[movingType][destinationType] = 2; - } - } - for (destinationType = 0; destinationType < PT_NUM; destinationType++) - { - //set what stickmen can move through - int stkm_move = 0; - if (elements[destinationType].Properties & (TYPE_LIQUID | TYPE_GAS)) - stkm_move = 2; - if (!destinationType || destinationType == PT_PRTO || destinationType == PT_SPAWN || destinationType == PT_SPAWN2) - stkm_move = 2; - can_move[PT_STKM][destinationType] = stkm_move; - can_move[PT_STKM2][destinationType] = stkm_move; - can_move[PT_FIGH][destinationType] = stkm_move; - - //spark shouldn't move - can_move[PT_SPRK][destinationType] = 0; - } - for (movingType = 1; movingType < PT_NUM; movingType++) - { - //everything "swaps" with VACU and BHOL to make them eat things - can_move[movingType][PT_BHOL] = 1; - can_move[movingType][PT_NBHL] = 1; - //nothing goes through stickmen - can_move[movingType][PT_STKM] = 0; - can_move[movingType][PT_STKM2] = 0; - can_move[movingType][PT_FIGH] = 0; - //INVS behaviour varies with pressure - can_move[movingType][PT_INVIS] = 3; - //stop CNCT from being displaced by other particles - can_move[movingType][PT_CNCT] = 0; - //VOID and PVOD behaviour varies with powered state and ctype - can_move[movingType][PT_PVOD] = 3; - can_move[movingType][PT_VOID] = 3; - //nothing moves through EMBR (not sure why, but it's killed when it touches anything) - can_move[movingType][PT_EMBR] = 0; - can_move[PT_EMBR][movingType] = 0; - //Energy particles move through VIBR and BVBR, so it can absorb them - if (elements[movingType].Properties & TYPE_ENERGY) - { - can_move[movingType][PT_VIBR] = 1; - can_move[movingType][PT_BVBR] = 1; - } - - //SAWD cannot be displaced by other powders - if (elements[movingType].Properties & TYPE_PART) - can_move[movingType][PT_SAWD] = 0; - } - //a list of lots of things PHOT can move through - // TODO: replace with property - for (destinationType = 0; destinationType < PT_NUM; destinationType++) - { - if (destinationType == PT_GLAS || destinationType == PT_PHOT || destinationType == PT_FILT || destinationType == PT_INVIS - || destinationType == PT_CLNE || destinationType == PT_PCLN || destinationType == PT_BCLN || destinationType == PT_PBCN - || destinationType == PT_WATR || destinationType == PT_DSTW || destinationType == PT_SLTW || destinationType == PT_GLOW - || destinationType == PT_ISOZ || destinationType == PT_ISZS || destinationType == PT_QRTZ || destinationType == PT_PQRT - || destinationType == PT_H2 || destinationType == PT_BGLA || destinationType == PT_C5) - can_move[PT_PHOT][destinationType] = 2; - if (destinationType != PT_DMND && destinationType != PT_INSL && destinationType != PT_VOID && destinationType != PT_PVOD && destinationType != PT_VIBR && destinationType != PT_BVBR && destinationType != PT_PRTI && destinationType != PT_PRTO) - { - can_move[PT_PROT][destinationType] = 2; - can_move[PT_GRVT][destinationType] = 2; - } - } - - //other special cases that weren't covered above - can_move[PT_DEST][PT_DMND] = 0; - can_move[PT_DEST][PT_CLNE] = 0; - can_move[PT_DEST][PT_PCLN] = 0; - can_move[PT_DEST][PT_BCLN] = 0; - can_move[PT_DEST][PT_PBCN] = 0; - can_move[PT_DEST][PT_ROCK] = 0; - - can_move[PT_NEUT][PT_INVIS] = 2; - can_move[PT_ELEC][PT_LCRY] = 2; - can_move[PT_ELEC][PT_EXOT] = 2; - can_move[PT_ELEC][PT_GLOW] = 2; - can_move[PT_PHOT][PT_LCRY] = 3; //varies according to LCRY life - can_move[PT_PHOT][PT_GPMP] = 3; - - can_move[PT_PHOT][PT_BIZR] = 2; - can_move[PT_ELEC][PT_BIZR] = 2; - can_move[PT_PHOT][PT_BIZRG] = 2; - can_move[PT_ELEC][PT_BIZRG] = 2; - can_move[PT_PHOT][PT_BIZRS] = 2; - can_move[PT_ELEC][PT_BIZRS] = 2; - can_move[PT_BIZR][PT_FILT] = 2; - can_move[PT_BIZRG][PT_FILT] = 2; - - can_move[PT_ANAR][PT_WHOL] = 1; //WHOL eats ANAR - can_move[PT_ANAR][PT_NWHL] = 1; - can_move[PT_ELEC][PT_DEUT] = 1; - can_move[PT_THDR][PT_THDR] = 2; - can_move[PT_EMBR][PT_EMBR] = 2; - can_move[PT_TRON][PT_SWCH] = 3; - can_move[PT_SOAP][PT_OIL] = 0; - can_move[PT_OIL][PT_SOAP] = 1; -} - /* RETURN-value explanation 1 = Swap @@ -1282,6 +1154,9 @@ int Simulation::eval_move(int pt, int nx, int ny, unsigned *rr) const *rr = r; if (pt>=PT_NUM || TYP(r)>=PT_NUM) return 0; + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; + auto &elements = sd.elements; result = can_move[pt][TYP(r)]; if (result == 3) { @@ -1365,6 +1240,8 @@ int Simulation::try_move(int i, int x, int y, int nx, int ny) if (!e && parts[i].type==PT_PHOT && ((TYP(r)==PT_BMTL && rng.chance(1, 2)) || TYP(pmap[y][x])==PT_BMTL)) e = 2; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!e) //if no movement { int rt = TYP(r); @@ -1700,6 +1577,8 @@ int Simulation::do_move(int i, int x, int y, float nxf, float nyf) bool Simulation::move(int i, int x, int y, float nxf, float nyf) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int nx = (int)(nxf+0.5f), ny = (int)(nyf+0.5f); int t = parts[i].type; parts[i].x = nxf; @@ -1883,6 +1762,8 @@ void Simulation::kill_part(int i)//kills particle number i int x = (int)(parts[i].x + 0.5f); int y = (int)(parts[i].y + 0.5f); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int t = parts[i].type; if (t && elements[t].ChangeType) { @@ -1914,6 +1795,9 @@ bool Simulation::part_change_type(int i, int x, int y, int t) { if (x<0 || y<0 || x>=XRES || y>=YRES || i>=NPART || t<0 || t>=PT_NUM || !parts[i].type) return false; + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!elements[t].Enabled || t == PT_NONE) { kill_part(i); @@ -1956,6 +1840,8 @@ int Simulation::create_part(int p, int x, int y, int t, int v) { int i, oldType = PT_NONE; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (x<0 || y<0 || x>=XRES || y>=YRES || t<=0 || t>=PT_NUM || !elements[t].Enabled) return -1; @@ -2238,6 +2124,8 @@ void Simulation::delete_part(int x, int y)//calls kill_part with the particle lo Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update_emap) { + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; // This function would be const if not for calling set_emap if update_emap is true, // and users of this function *expect* it to be const if update_emap is false. So // whenever you change something here, make sure it compiles *as const* if you @@ -2348,6 +2236,8 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update void Simulation::UpdateParticles(int start, int end) { //the main particle loop function, goes over all particles. + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto i = start; i < end && i <= parts_lastActiveIndex; i++) { if (parts[i].type) @@ -2585,16 +2475,16 @@ void Simulation::UpdateParticles(int start, int end) auto ctemph = pt; auto ctempl = pt; // change boiling point with pressure - if (((elements[t].Properties&TYPE_LIQUID) && IsElementOrNone(elements[t].HighTemperatureTransition) && (elements[elements[t].HighTemperatureTransition].Properties&TYPE_GAS)) + if (((elements[t].Properties&TYPE_LIQUID) && sd.IsElementOrNone(elements[t].HighTemperatureTransition) && (elements[elements[t].HighTemperatureTransition].Properties&TYPE_GAS)) || t==PT_LNTG || t==PT_SLTW) ctemph -= 2.0f*pv[y/CELL][x/CELL]; - else if (((elements[t].Properties&TYPE_GAS) && IsElementOrNone(elements[t].LowTemperatureTransition) && (elements[elements[t].LowTemperatureTransition].Properties&TYPE_LIQUID)) + else if (((elements[t].Properties&TYPE_GAS) && sd.IsElementOrNone(elements[t].LowTemperatureTransition) && (elements[elements[t].LowTemperatureTransition].Properties&TYPE_LIQUID)) || t==PT_WTRV) ctempl -= 2.0f*pv[y/CELL][x/CELL]; auto s = 1; //A fix for ice with ctype = 0 - if ((t==PT_ICEI || t==PT_SNOW) && (!IsElement(parts[i].ctype) || parts[i].ctype==PT_ICEI || parts[i].ctype==PT_SNOW)) + if ((t==PT_ICEI || t==PT_SNOW) && (!sd.IsElement(parts[i].ctype) || parts[i].ctype==PT_ICEI || parts[i].ctype==PT_SNOW)) parts[i].ctype = PT_WATR; if (elements[t].HighTemperatureTransition>-1 && ctemph>=elements[t].HighTemperature) @@ -3470,6 +3360,8 @@ void Simulation::RecalcFreeParticles(bool do_life_dec) memset(photons, 0, sizeof(photons)); NUM_PARTS = 0; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; //the particle loop that resets the pmap/photon maps every frame, to update them. for (int i = 0; i <= parts_lastActiveIndex; i++) { @@ -3552,6 +3444,7 @@ void Simulation::RecalcFreeParticles(bool do_life_dec) void Simulation::SimulateGoL() { + auto &builtinGol = SimulationData::builtinGol; CGOL = 0; for (int i = 0; i <= parts_lastActiveIndex; ++i) { @@ -3728,6 +3621,8 @@ void Simulation::SimulateGoL() void Simulation::CheckStacking() { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; bool excessive_stacking_found = false; force_stacking_check = false; for (int y = 0; y < YRES; y++) @@ -3997,10 +3892,7 @@ void Simulation::AfterSim() frameCount += 1; } -Simulation::~Simulation() -{ - delete air; -} +Simulation::~Simulation() = default; Simulation::Simulation(): replaceModeSelected(0), @@ -4050,7 +3942,7 @@ Simulation::Simulation(): gravmap = &grav->gravmap[0]; //Create and attach air simulation - air = new Air(*this); + air = std::make_unique(*this); //Give air sim references to our data air->bmap = bmap; air->emap = emap; @@ -4062,88 +3954,14 @@ Simulation::Simulation(): pv = air->pv; hv = air->hv; - msections = LoadMenus(); - wtypes = LoadWalls(); - platent = LoadLatent(); - std::copy(GetElements().begin(), GetElements().end(), elements.begin()); - tools = GetTools(); - player.comm = 0; player2.comm = 0; - init_can_move(); clear_sim(); grav->gravity_mask(); } -const Simulation::CustomGOLData *Simulation::GetCustomGOLByRule(int rule) const -{ - // * Binary search. customGol is already sorted, see SetCustomGOL. - auto it = std::lower_bound(customGol.begin(), customGol.end(), rule, [](const CustomGOLData &item, int rule) { - return item.rule < rule; - }); - if (it != customGol.end() && !(rule < it->rule)) - { - return &*it; - } - return nullptr; -} - -void Simulation::SetCustomGOL(std::vector newCustomGol) -{ - std::sort(newCustomGol.begin(), newCustomGol.end()); - customGol = newCustomGol; -} - -String Simulation::ElementResolve(int type, int ctype) const -{ - if (type == PT_LIFE) - { - if (ctype >= 0 && ctype < NGOL) - { - return builtinGol[ctype].name; - } - auto *cgol = GetCustomGOLByRule(ctype); - if (cgol) - { - return cgol->nameString; - } - return SerialiseGOLRule(ctype); - } - else if (type >= 0 && type < PT_NUM) - return elements[type].Name; - return "Empty"; -} - -String Simulation::BasicParticleInfo(Particle const &sample_part) const -{ - StringBuilder sampleInfo; - int type = sample_part.type; - int ctype = sample_part.ctype; - int storedCtype = sample_part.tmp4; - if (type == PT_LAVA && IsElement(ctype)) - { - sampleInfo << "Molten " << ElementResolve(ctype, -1); - } - else if ((type == PT_PIPE || type == PT_PPIP) && IsElement(ctype)) - { - if (ctype == PT_LAVA && IsElement(storedCtype)) - { - sampleInfo << ElementResolve(type, -1) << " with molten " << ElementResolve(storedCtype, -1); - } - else - { - sampleInfo << ElementResolve(type, -1) << " with " << ElementResolve(ctype, storedCtype); - } - } - else - { - sampleInfo << ElementResolve(type, ctype); - } - return sampleInfo.Build(); -} - int Simulation::remainder_p(int x, int y) { return (x % y) + (x>=0 ? 0 : y); diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 194d197ed..4a71591ba 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -22,7 +22,6 @@ constexpr int CHANNELS = int(MAX_TEMP - 73) / 100 + 2; class Snapshot; -class SimTool; class Brush; class SimulationSample; struct matrix2d; @@ -37,24 +36,17 @@ class GameSave; class Simulation { public: - GravityPtr grav; - Air * air; + std::unique_ptr air; RNG rng; std::vector signs; - std::array elements; //Element * elements; - std::vector tools; - std::vector platent; - std::vector wtypes; - std::vector msections; int currentTick; int replaceModeSelected; int replaceModeFlags; - char can_move[PT_NUM][PT_NUM]; int debug_nextToUpdate; int debug_mostRecentlyUpdated = -1; // -1 when between full update loops int parts_lastActiveIndex; @@ -127,7 +119,7 @@ public: void SaveSimOptions(GameSave &gameSave); SimulationSample GetSample(int x, int y); - std::unique_ptr CreateSnapshot(); + std::unique_ptr CreateSnapshot() const; void Restore(const Snapshot &snap); int is_blocking(int t, int x, int y); @@ -145,18 +137,11 @@ public: float vx, vy; }; PlanMoveResult PlanMove(int i, int x, int y, bool update_emap); - void init_can_move(); bool IsWallBlocking(int x, int y, int type) const; - bool IsElement(int type) const { - return (type > 0 && type < PT_NUM && elements[type].Enabled); - } - bool IsElementOrNone(int type) const { - return (type >= 0 && type < PT_NUM && elements[type].Enabled); - } void create_cherenkov_photon(int pp); void create_gain_photon(int pp); void kill_part(int i); - bool FloodFillPmapCheck(int x, int y, int type); + bool FloodFillPmapCheck(int x, int y, int type) const; int flood_prop(int x, int y, StructProperty prop, PropertyValue propvalue); bool flood_water(int x, int y, int i); int FloodINST(int x, int y); @@ -177,7 +162,6 @@ public: void CheckStacking(); void BeforeSim(); void AfterSim(); - void rotate_area(int area_x, int area_y, int area_w, int area_h, int invert); void clear_area(int area_x, int area_y, int area_w, int area_h); void SetEdgeMode(int newEdgeMode); @@ -212,11 +196,8 @@ public: void CreateBox(int x1, int y1, int x2, int y2, int c, int flags = -1); int FloodParts(int x, int y, int c, int cm, int flags = -1); - void GetGravityField(int x, int y, float particleGrav, float newtonGrav, float & pGravX, float & pGravY); - int GetParticleType(ByteString type); - void orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]); void orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]); int get_wavelength_bin(int *wm); @@ -236,29 +217,6 @@ public: static int remainder_p(int x, int y); static float remainder_p(float x, float y); - String ElementResolve(int type, int ctype) const; - String BasicParticleInfo(Particle const &sample_part) const; - - - struct CustomGOLData - { - int rule, colour1, colour2; - String nameString, ruleString; - - inline bool operator <(const CustomGOLData &other) const - { - return rule < other.rule; - } - }; - -private: - std::vector customGol; - -public: - const CustomGOLData *GetCustomGOLByRule(int rule) const; - const std::vector GetCustomGol() { return customGol; } - void SetCustomGOL(std::vector newCustomGol); - private: CoordStack& getCoordStackSingleton(); }; diff --git a/src/simulation/SimulationData.cpp b/src/simulation/SimulationData.cpp index bbfaeed4c..a6a9ba39c 100644 --- a/src/simulation/SimulationData.cpp +++ b/src/simulation/SimulationData.cpp @@ -1,16 +1,16 @@ #include "SimulationData.h" - #include "ElementGraphics.h" #include "ElementDefs.h" #include "ElementClasses.h" - +#include "GOLString.h" #include "BuiltinGOL.h" #include "WallType.h" #include "MenuSection.h" - +#include "ToolClasses.h" +#include "Misc.h" #include "graphics/Renderer.h" -const BuiltinGOL builtinGol[NGOL] = { +const std::array SimulationData::builtinGol = {{ // * Ruleset: // * bits x = 8..0: stay if x neighbours present // * bits x = 16..9: begin if x-8 neighbours present @@ -45,9 +45,9 @@ const BuiltinGOL builtinGol[NGOL] = { { "STAR", GT_STAR, 0x98478, 0x000040_rgb, 0x0000E6_rgb, NGT_STAR, String("Like Star Wars rule: B278/S3456/6") }, { "FROG", GT_FROG, 0x21806, 0x006400_rgb, 0x00FF00_rgb, NGT_FROG, String("Frogs: B34/S12/3") }, { "BRAN", GT_BRAN, 0x25440, 0xFFFF00_rgb, 0x969600_rgb, NGT_BRAN, String("Brian 6: B246/S6/3" )} -}; +}}; -std::vector LoadWalls() +static std::vector LoadWalls() { return std::vector{ @@ -73,7 +73,7 @@ std::vector LoadWalls() }; } -std::vector LoadMenus() +static std::vector LoadMenus() { return std::vector{ @@ -98,7 +98,7 @@ std::vector LoadMenus() }; } -std::vector LoadLatent() +static std::vector LoadLatent() { return std::vector{ @@ -265,3 +265,246 @@ std::vector LoadLatent() /* REPL */ 0, }; } + +void SimulationData::init_can_move() +{ + int movingType, destinationType; + // can_move[moving type][type at destination] + // 0 = No move/Bounce + // 1 = Swap + // 2 = Both particles occupy the same space. + // 3 = Varies, go run some extra checks + + //particles that don't exist shouldn't move... + for (destinationType = 0; destinationType < PT_NUM; destinationType++) + can_move[0][destinationType] = 0; + + //initialize everything else to swapping by default + for (movingType = 1; movingType < PT_NUM; movingType++) + for (destinationType = 0; destinationType < PT_NUM; destinationType++) + can_move[movingType][destinationType] = 1; + + //photons go through everything by default + for (destinationType = 1; destinationType < PT_NUM; destinationType++) + can_move[PT_PHOT][destinationType] = 2; + + for (movingType = 1; movingType < PT_NUM; movingType++) + { + for (destinationType = 1; destinationType < PT_NUM; destinationType++) + { + //weight check, also prevents particles of same type displacing each other + if (elements[movingType].Weight <= elements[destinationType].Weight || destinationType == PT_GEL) + can_move[movingType][destinationType] = 0; + + //other checks for NEUT and energy particles + if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTPASS)) + can_move[movingType][destinationType] = 2; + if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTABSORB)) + can_move[movingType][destinationType] = 1; + if (movingType == PT_NEUT && (elements[destinationType].Properties&PROP_NEUTPENETRATE)) + can_move[movingType][destinationType] = 1; + if (destinationType == PT_NEUT && (elements[movingType].Properties&PROP_NEUTPENETRATE)) + can_move[movingType][destinationType] = 0; + if ((elements[movingType].Properties&TYPE_ENERGY) && (elements[destinationType].Properties&TYPE_ENERGY)) + can_move[movingType][destinationType] = 2; + } + } + for (destinationType = 0; destinationType < PT_NUM; destinationType++) + { + //set what stickmen can move through + int stkm_move = 0; + if (elements[destinationType].Properties & (TYPE_LIQUID | TYPE_GAS)) + stkm_move = 2; + if (!destinationType || destinationType == PT_PRTO || destinationType == PT_SPAWN || destinationType == PT_SPAWN2) + stkm_move = 2; + can_move[PT_STKM][destinationType] = stkm_move; + can_move[PT_STKM2][destinationType] = stkm_move; + can_move[PT_FIGH][destinationType] = stkm_move; + + //spark shouldn't move + can_move[PT_SPRK][destinationType] = 0; + } + for (movingType = 1; movingType < PT_NUM; movingType++) + { + //everything "swaps" with VACU and BHOL to make them eat things + can_move[movingType][PT_BHOL] = 1; + can_move[movingType][PT_NBHL] = 1; + //nothing goes through stickmen + can_move[movingType][PT_STKM] = 0; + can_move[movingType][PT_STKM2] = 0; + can_move[movingType][PT_FIGH] = 0; + //INVS behaviour varies with pressure + can_move[movingType][PT_INVIS] = 3; + //stop CNCT from being displaced by other particles + can_move[movingType][PT_CNCT] = 0; + //VOID and PVOD behaviour varies with powered state and ctype + can_move[movingType][PT_PVOD] = 3; + can_move[movingType][PT_VOID] = 3; + //nothing moves through EMBR (not sure why, but it's killed when it touches anything) + can_move[movingType][PT_EMBR] = 0; + can_move[PT_EMBR][movingType] = 0; + //Energy particles move through VIBR and BVBR, so it can absorb them + if (elements[movingType].Properties & TYPE_ENERGY) + { + can_move[movingType][PT_VIBR] = 1; + can_move[movingType][PT_BVBR] = 1; + } + + //SAWD cannot be displaced by other powders + if (elements[movingType].Properties & TYPE_PART) + can_move[movingType][PT_SAWD] = 0; + } + //a list of lots of things PHOT can move through + // TODO: replace with property + for (destinationType = 0; destinationType < PT_NUM; destinationType++) + { + if (destinationType == PT_GLAS || destinationType == PT_PHOT || destinationType == PT_FILT || destinationType == PT_INVIS + || destinationType == PT_CLNE || destinationType == PT_PCLN || destinationType == PT_BCLN || destinationType == PT_PBCN + || destinationType == PT_WATR || destinationType == PT_DSTW || destinationType == PT_SLTW || destinationType == PT_GLOW + || destinationType == PT_ISOZ || destinationType == PT_ISZS || destinationType == PT_QRTZ || destinationType == PT_PQRT + || destinationType == PT_H2 || destinationType == PT_BGLA || destinationType == PT_C5) + can_move[PT_PHOT][destinationType] = 2; + if (destinationType != PT_DMND && destinationType != PT_INSL && destinationType != PT_VOID && destinationType != PT_PVOD && destinationType != PT_VIBR && destinationType != PT_BVBR && destinationType != PT_PRTI && destinationType != PT_PRTO) + { + can_move[PT_PROT][destinationType] = 2; + can_move[PT_GRVT][destinationType] = 2; + } + } + + //other special cases that weren't covered above + can_move[PT_DEST][PT_DMND] = 0; + can_move[PT_DEST][PT_CLNE] = 0; + can_move[PT_DEST][PT_PCLN] = 0; + can_move[PT_DEST][PT_BCLN] = 0; + can_move[PT_DEST][PT_PBCN] = 0; + can_move[PT_DEST][PT_ROCK] = 0; + + can_move[PT_NEUT][PT_INVIS] = 2; + can_move[PT_ELEC][PT_LCRY] = 2; + can_move[PT_ELEC][PT_EXOT] = 2; + can_move[PT_ELEC][PT_GLOW] = 2; + can_move[PT_PHOT][PT_LCRY] = 3; //varies according to LCRY life + can_move[PT_PHOT][PT_GPMP] = 3; + + can_move[PT_PHOT][PT_BIZR] = 2; + can_move[PT_ELEC][PT_BIZR] = 2; + can_move[PT_PHOT][PT_BIZRG] = 2; + can_move[PT_ELEC][PT_BIZRG] = 2; + can_move[PT_PHOT][PT_BIZRS] = 2; + can_move[PT_ELEC][PT_BIZRS] = 2; + can_move[PT_BIZR][PT_FILT] = 2; + can_move[PT_BIZRG][PT_FILT] = 2; + + can_move[PT_ANAR][PT_WHOL] = 1; //WHOL eats ANAR + can_move[PT_ANAR][PT_NWHL] = 1; + can_move[PT_ELEC][PT_DEUT] = 1; + can_move[PT_THDR][PT_THDR] = 2; + can_move[PT_EMBR][PT_EMBR] = 2; + can_move[PT_TRON][PT_SWCH] = 3; + can_move[PT_SOAP][PT_OIL] = 0; + can_move[PT_OIL][PT_SOAP] = 1; +} + +const CustomGOLData *SimulationData::GetCustomGOLByRule(int rule) const +{ + // * Binary search. customGol is already sorted, see SetCustomGOL. + auto it = std::lower_bound(customGol.begin(), customGol.end(), rule, [](const CustomGOLData &item, int rule) { + return item.rule < rule; + }); + if (it != customGol.end() && !(rule < it->rule)) + { + return &*it; + } + return nullptr; +} + +void SimulationData::SetCustomGOL(std::vector newCustomGol) +{ + std::sort(newCustomGol.begin(), newCustomGol.end()); + customGol = newCustomGol; +} + +String SimulationData::ElementResolve(int type, int ctype) const +{ + if (type == PT_LIFE) + { + if (ctype >= 0 && ctype < NGOL) + { + return builtinGol[ctype].name; + } + auto *cgol = GetCustomGOLByRule(ctype); + if (cgol) + { + return cgol->nameString; + } + return SerialiseGOLRule(ctype); + } + else if (type >= 0 && type < PT_NUM) + return elements[type].Name; + return "Empty"; +} + +String SimulationData::BasicParticleInfo(Particle const &sample_part) const +{ + StringBuilder sampleInfo; + int type = sample_part.type; + int ctype = sample_part.ctype; + int storedCtype = sample_part.tmp4; + if (type == PT_LAVA && IsElement(ctype)) + { + sampleInfo << "Molten " << ElementResolve(ctype, -1); + } + else if ((type == PT_PIPE || type == PT_PPIP) && IsElement(ctype)) + { + if (ctype == PT_LAVA && IsElement(storedCtype)) + { + sampleInfo << ElementResolve(type, -1) << " with molten " << ElementResolve(storedCtype, -1); + } + else + { + sampleInfo << ElementResolve(type, -1) << " with " << ElementResolve(ctype, storedCtype); + } + } + else + { + sampleInfo << ElementResolve(type, ctype); + } + return sampleInfo.Build(); +} + +int SimulationData::GetParticleType(ByteString type) const +{ + type = type.ToUpper(); + + // alternative names for some elements + if (byteStringEqualsLiteral(type, "C4")) + { + return PT_PLEX; + } + else if (byteStringEqualsLiteral(type, "C5")) + { + return PT_C5; + } + else if (byteStringEqualsLiteral(type, "NONE")) + { + return PT_NONE; + } + for (int i = 1; i < PT_NUM; i++) + { + if (elements[i].Name.size() && elements[i].Enabled && type == elements[i].Name.ToUtf8().ToUpper()) + { + return i; + } + } + return -1; +} + +SimulationData::SimulationData() +{ + init_can_move(); + msections = LoadMenus(); + wtypes = LoadWalls(); + platent = LoadLatent(); + elements = GetElements(); + tools = GetTools(); +} diff --git a/src/simulation/SimulationData.h b/src/simulation/SimulationData.h index 90dbed540..9f92f7725 100644 --- a/src/simulation/SimulationData.h +++ b/src/simulation/SimulationData.h @@ -1,8 +1,18 @@ #pragma once #include "SimulationConfig.h" +#include "ElementDefs.h" +#include "common/ExplicitSingleton.h" +#include "common/String.h" +#include "MenuSection.h" +#include "BuiltinGOL.h" +#include "SimTool.h" +#include "Element.h" +#include "Particle.h" +#include "WallType.h" #include #include #include +#include constexpr int SC_WALL = 0; constexpr int SC_ELEC = 1; @@ -148,20 +158,61 @@ enum GravityMode GRAV_VERTICAL, GRAV_OFF, GRAV_RADIAL, GRAV_CUSTOM, NUM_GRAV_MODES }; -struct part_type; -struct part_transition; +struct CustomGOLData +{ + int rule, colour1, colour2; + String nameString, ruleString; -struct wall_type; -struct BuiltinGOL; -struct menu_section; + inline bool operator <(const CustomGOLData &other) const + { + return rule < other.rule; + } +}; -class SimTool; -class Element; +class SimulationData : public ExplicitSingleton +{ +public: + std::array elements; + std::vector tools; + std::vector platent; + std::vector wtypes; + std::vector msections; + char can_move[PT_NUM][PT_NUM]; + static const std::array builtinGol; -extern const BuiltinGOL builtinGol[]; + // Element properties that enable basic graphics (i.e. every property that has to do with graphics other than + // the graphics callback itself) are only ever written by the main thread, but they are read by some other + // threads that use Renderer to render thumbnails and such. Take this std::shared_mutex with an std::unique_lock + // when writing such properties in the main thread, and with an std::shared_lock when reading such properties + // in these secondary Renderer threads. Don't take it with an std::shared_lock when reading such properties in + // the main thread; the main thread doesn't race with itself. + mutable std::shared_mutex elementGraphicsMx; -std::vector LoadWalls(); +private: + std::vector customGol; -std::vector LoadMenus(); +public: + SimulationData(); + void InitElements(); -std::vector LoadLatent(); + void init_can_move(); + + const CustomGOLData *GetCustomGOLByRule(int rule) const; + const std::vector &GetCustomGol() const { return customGol; } + void SetCustomGOL(std::vector newCustomGol); + + String ElementResolve(int type, int ctype) const; + String BasicParticleInfo(Particle const &sample_part) const; + int GetParticleType(ByteString type) const; + + bool IsElement(int type) const + { + return (type > 0 && type < PT_NUM && elements[type].Enabled); + } + + bool IsElementOrNone(int type) const + { + return (type >= 0 && type < PT_NUM && elements[type].Enabled); + } + +}; diff --git a/src/simulation/elements/ACEL.cpp b/src/simulation/elements/ACEL.cpp index b0c9a4cb9..24a8b45f8 100644 --- a/src/simulation/elements/ACEL.cpp +++ b/src/simulation/elements/ACEL.cpp @@ -49,6 +49,8 @@ void Element::Element_ACEL() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; float multiplier; if (parts[i].life!=0) { @@ -71,7 +73,7 @@ static int update(UPDATE_FUNC_ARGS) r = sim->photons[y+ry][x+rx]; if (!r) continue; - if(sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) + if(elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) { parts[ID(r)].vx *= multiplier; parts[ID(r)].vy *= multiplier; diff --git a/src/simulation/elements/ACID.cpp b/src/simulation/elements/ACID.cpp index 7baa317e8..620ced22c 100644 --- a/src/simulation/elements/ACID.cpp +++ b/src/simulation/elements/ACID.cpp @@ -52,6 +52,8 @@ void Element::Element_ACID() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto rx = -2; rx <= 2; rx++) { for (auto ry = -2; ry <= 2; ry++) @@ -80,11 +82,11 @@ static int update(UPDATE_FUNC_ARGS) sim->kill_part(ID(r)); } } - else if (rt != PT_CLNE && rt != PT_PCLN && parts[i].life >= 50 && sim->rng.chance(sim->elements[rt].Hardness, 1000)) + else if (rt != PT_CLNE && rt != PT_PCLN && parts[i].life >= 50 && sim->rng.chance(elements[rt].Hardness, 1000)) { if (sim->parts_avg(i, ID(r),PT_GLAS)!= PT_GLAS)//GLAS protects stuff from acid { - float newtemp = ((60.0f-(float)sim->elements[rt].Hardness))*7.0f; + float newtemp = ((60.0f-(float)elements[rt].Hardness))*7.0f; if(newtemp < 0){ newtemp = 0; } diff --git a/src/simulation/elements/ARAY.cpp b/src/simulation/elements/ARAY.cpp index 7784adefc..e60cee4ee 100644 --- a/src/simulation/elements/ARAY.cpp +++ b/src/simulation/elements/ARAY.cpp @@ -47,6 +47,8 @@ void Element::Element_ARAY() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int short_bray_life = parts[i].life > 0 ? parts[i].life : 30; int long_bray_life = parts[i].life > 0 ? parts[i].life : 1020; for (int rx = -1; rx <= 1; rx++) @@ -170,7 +172,7 @@ static int update(UPDATE_FUNC_ARGS) if (nyy!=0 || nxx!=0) sim->create_part(-1, x+nxi+nxx, y+nyi+nyy, PT_SPRK); - if (!(nostop && parts[r].type==PT_SPRK && parts[r].ctype >= 0 && parts[r].ctype < PT_NUM && (sim->elements[parts[r].ctype].Properties&PROP_CONDUCTS))) + if (!(nostop && parts[r].type==PT_SPRK && parts[r].ctype >= 0 && parts[r].ctype < PT_NUM && (elements[parts[r].ctype].Properties&PROP_CONDUCTS))) docontinue = 0; else docontinue = 1; diff --git a/src/simulation/elements/BCLN.cpp b/src/simulation/elements/BCLN.cpp index aebb675b9..78be0805d 100644 --- a/src/simulation/elements/BCLN.cpp +++ b/src/simulation/elements/BCLN.cpp @@ -51,6 +51,8 @@ constexpr float ADVECTION = 0.1f; static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!parts[i].life && sim->pv[y/CELL][x/CELL]>4.0f) parts[i].life = sim->rng.between(80, 119); if (parts[i].life) @@ -58,7 +60,7 @@ static int update(UPDATE_FUNC_ARGS) parts[i].vx += ADVECTION*sim->vx[y/CELL][x/CELL]; parts[i].vy += ADVECTION*sim->vy[y/CELL][x/CELL]; } - if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled) + if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !elements[parts[i].ctype].Enabled) { for (auto rx = -1; rx <= 1; rx++) { @@ -90,7 +92,7 @@ static int update(UPDATE_FUNC_ARGS) int np = sim->create_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype)); if (np>=0) { - if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpparts_avg(i,ID(r),PT_INSL) != PT_INSL) { - if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) + if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) { parts[ID(r)].life = 4; parts[ID(r)].ctype = rt; diff --git a/src/simulation/elements/C5.cpp b/src/simulation/elements/C5.cpp index 3b164a953..963245bfc 100644 --- a/src/simulation/elements/C5.cpp +++ b/src/simulation/elements/C5.cpp @@ -49,6 +49,8 @@ void Element::Element_C5() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto rx = -2; rx <= 2; rx++) { for (auto ry = -2; ry <= 2; ry++) @@ -58,7 +60,7 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if (!r) continue; - if ((TYP(r)!=PT_C5 && parts[ID(r)].temp<100 && sim->elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) || TYP(r)==PT_CFLM) + if ((TYP(r)!=PT_C5 && parts[ID(r)].temp<100 && elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) || TYP(r)==PT_CFLM) { if (sim->rng.chance(1, 6)) { diff --git a/src/simulation/elements/CAUS.cpp b/src/simulation/elements/CAUS.cpp index afa318dee..5069ea67e 100644 --- a/src/simulation/elements/CAUS.cpp +++ b/src/simulation/elements/CAUS.cpp @@ -49,6 +49,8 @@ void Element::Element_CAUS() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (int rx = -2; rx <= 2; rx++) { for (int ry = -2; ry <= 2; ry++) @@ -68,12 +70,12 @@ static int update(UPDATE_FUNC_ARGS) } else if (TYP(r) != PT_ACID && TYP(r) != PT_CAUS && TYP(r) != PT_RFRG && TYP(r) != PT_RFGL) { - if ((TYP(r) != PT_CLNE && TYP(r) != PT_PCLN && sim->rng.chance(sim->elements[TYP(r)].Hardness, 1000)) && parts[i].life >= 50) + if ((TYP(r) != PT_CLNE && TYP(r) != PT_PCLN && sim->rng.chance(elements[TYP(r)].Hardness, 1000)) && parts[i].life >= 50) { // GLAS protects stuff from acid if (sim->parts_avg(i, ID(r),PT_GLAS) != PT_GLAS) { - float newtemp = ((60.0f - (float)sim->elements[TYP(r)].Hardness)) * 7.0f; + float newtemp = ((60.0f - (float)elements[TYP(r)].Hardness)) * 7.0f; if (newtemp < 0) newtemp = 0; parts[i].temp += newtemp; diff --git a/src/simulation/elements/CBNW.cpp b/src/simulation/elements/CBNW.cpp index 274364677..ac3b09d1e 100644 --- a/src/simulation/elements/CBNW.cpp +++ b/src/simulation/elements/CBNW.cpp @@ -50,6 +50,8 @@ void Element::Element_CBNW() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (sim->pv[y/CELL][x/CELL]<=3) { if (sim->pv[y/CELL][x/CELL] <= -0.5 || sim->rng.chance(1, 4000)) @@ -87,12 +89,12 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if (!r) continue; - if ((sim->elements[TYP(r)].Properties&TYPE_PART) && parts[i].tmp == 0 && sim->rng.chance(1, 83)) + if ((elements[TYP(r)].Properties&TYPE_PART) && parts[i].tmp == 0 && sim->rng.chance(1, 83)) { //Start explode parts[i].tmp = sim->rng.between(0, 24); } - else if((sim->elements[TYP(r)].Properties&TYPE_SOLID) && TYP(r)!=PT_DMND && TYP(r)!=PT_GLAS && parts[i].tmp == 0 && sim->rng.chance(int(2 - sim->pv[y/CELL][x/CELL]), 6667)) + else if((elements[TYP(r)].Properties&TYPE_SOLID) && TYP(r)!=PT_DMND && TYP(r)!=PT_GLAS && parts[i].tmp == 0 && sim->rng.chance(int(2 - sim->pv[y/CELL][x/CELL]), 6667)) { sim->part_change_type(i,x,y,PT_CO2); parts[i].ctype = 5; diff --git a/src/simulation/elements/CLNE.cpp b/src/simulation/elements/CLNE.cpp index 72caac538..c3b910b8c 100644 --- a/src/simulation/elements/CLNE.cpp +++ b/src/simulation/elements/CLNE.cpp @@ -49,7 +49,9 @@ void Element::Element_CLNE() static int update(UPDATE_FUNC_ARGS) { - if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !elements[parts[i].ctype].Enabled) { for (auto rx = -1; rx <= 1; rx++) { @@ -81,7 +83,7 @@ static int update(UPDATE_FUNC_ARGS) int np = sim->create_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype)); if (np>=0) { - if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp=PT_NUM || !sim->elements[ctype].Enabled || ctype==PT_CONV) + if (ctype<=0 || ctype>=PT_NUM || !elements[ctype].Enabled || ctype==PT_CONV) { for (auto rx = -1; rx <= 1; rx++) { @@ -76,7 +78,7 @@ static int update(UPDATE_FUNC_ARGS) } else { - int restrictElement = sim->IsElement(parts[i].tmp) ? parts[i].tmp : 0; + int restrictElement = sd.IsElement(parts[i].tmp) ? parts[i].tmp : 0; for (auto rx = -1; rx <= 1; rx++) { for (auto ry = -1; ry <= 1; ry++) diff --git a/src/simulation/elements/CRAY.cpp b/src/simulation/elements/CRAY.cpp index 4e3d68d2e..878ffe5b5 100644 --- a/src/simulation/elements/CRAY.cpp +++ b/src/simulation/elements/CRAY.cpp @@ -51,9 +51,11 @@ void Element::Element_CRAY() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int nxx, nyy, docontinue, nxi, nyi; // set ctype to things that touch it if it doesn't have one already - if (parts[i].ctype<=0 || !sim->elements[TYP(parts[i].ctype)].Enabled) + if (parts[i].ctype<=0 || !elements[TYP(parts[i].ctype)].Enabled) { for (int rx = -1; rx <= 1; rx++) { @@ -166,6 +168,8 @@ static unsigned int wavelengthToDecoColour(int wavelength) static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!Element::ctypeDrawVInCtype(CTYPEDRAW_FUNC_SUBCALL_ARGS)) { return false; @@ -174,6 +178,6 @@ static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS) { sim->parts[i].ctype |= PMAPID(30); } - sim->parts[i].temp = sim->elements[t].DefaultProperties.temp; + sim->parts[i].temp = elements[t].DefaultProperties.temp; return true; } diff --git a/src/simulation/elements/DCEL.cpp b/src/simulation/elements/DCEL.cpp index c52c5ccbd..202959908 100644 --- a/src/simulation/elements/DCEL.cpp +++ b/src/simulation/elements/DCEL.cpp @@ -49,6 +49,8 @@ void Element::Element_DCEL() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; float multiplier = 1.0f/1.1f; if (parts[i].life!=0) { @@ -66,7 +68,7 @@ static int update(UPDATE_FUNC_ARGS) r = sim->photons[y+ry][x+rx]; if (!r) continue; - if (sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) + if (elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) { parts[ID(r)].vx *= multiplier; parts[ID(r)].vy *= multiplier; diff --git a/src/simulation/elements/DEST.cpp b/src/simulation/elements/DEST.cpp index 1f09a87db..b2c91c13b 100644 --- a/src/simulation/elements/DEST.cpp +++ b/src/simulation/elements/DEST.cpp @@ -49,6 +49,8 @@ void Element::Element_DEST() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rx = sim->rng.between(-2, 2); int ry = sim->rng.between(-2, 2); int r = pmap[y+ry][x+rx]; @@ -81,11 +83,11 @@ static int update(UPDATE_FUNC_ARGS) else if (sim->rng.chance(1, 3)) { sim->kill_part(ID(r)); - parts[i].life -= 4*((sim->elements[rt].Properties&TYPE_SOLID)?3:1); + parts[i].life -= 4*((elements[rt].Properties&TYPE_SOLID)?3:1); if (parts[i].life<=0) parts[i].life=1; } - else if (sim->elements[rt].HeatConduct) + else if (elements[rt].HeatConduct) parts[ID(r)].temp = MAX_TEMP; parts[i].temp=MAX_TEMP; sim->pv[y/CELL][x/CELL]+=80.0f; diff --git a/src/simulation/elements/DMG.cpp b/src/simulation/elements/DMG.cpp index 0067555ad..ba0e4f043 100644 --- a/src/simulation/elements/DMG.cpp +++ b/src/simulation/elements/DMG.cpp @@ -50,6 +50,8 @@ void Element::Element_DMG() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rad = 25; for (auto rx = -1; rx <= 1; rx++) { @@ -84,8 +86,8 @@ static int update(UPDATE_FUNC_ARGS) sim->vy[(y+nxj)/CELL][(x+nxi)/CELL] += fy; sim->pv[(y+nxj)/CELL][(x+nxi)/CELL] += 1.0f; auto t = TYP(rr); - if (t && sim->elements[t].HighPressureTransition>-1 && sim->elements[t].HighPressureTransitionpart_change_type(ID(rr), x+nxi, y+nxj, sim->elements[t].HighPressureTransition); + if (t && elements[t].HighPressureTransition>-1 && elements[t].HighPressureTransitionpart_change_type(ID(rr), x+nxi, y+nxj, elements[t].HighPressureTransition); else if (t == PT_BMTL) sim->part_change_type(ID(rr), x+nxi, y+nxj, PT_BRMT); else if (t == PT_GLAS) diff --git a/src/simulation/elements/DRAY.cpp b/src/simulation/elements/DRAY.cpp index 97218461d..6654370fd 100644 --- a/src/simulation/elements/DRAY.cpp +++ b/src/simulation/elements/DRAY.cpp @@ -50,6 +50,8 @@ void Element::Element_DRAY() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int ctype = TYP(parts[i].ctype), ctypeExtra = ID(parts[i].ctype), copyLength = parts[i].tmp, copySpaces = parts[i].tmp2; if (copySpaces < 0) copySpaces = parts[i].tmp2 = 0; @@ -98,7 +100,7 @@ static int update(UPDATE_FUNC_ARGS) foundParticle = true; } // now that it knows what kind of particle it is copying, do some extra stuff here so we can determine when to stop - if ((ctype && sim->elements[ctype].Properties&TYPE_ENERGY) || isEnergy) + if ((ctype && elements[ctype].Properties&TYPE_ENERGY) || isEnergy) rr = sim->photons[yCurrent][xCurrent]; else rr = pmap[yCurrent][xCurrent]; diff --git a/src/simulation/elements/DTEC.cpp b/src/simulation/elements/DTEC.cpp index 911bd2dde..44a15d327 100644 --- a/src/simulation/elements/DTEC.cpp +++ b/src/simulation/elements/DTEC.cpp @@ -51,6 +51,8 @@ void Element::Element_DTEC() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rd = parts[i].tmp2; if (rd > 25) parts[i].tmp2 = rd = 25; if (parts[i].life) @@ -68,7 +70,7 @@ static int update(UPDATE_FUNC_ARGS) auto rt = TYP(r); if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL) { - if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) + if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) { parts[ID(r)].life = 4; parts[ID(r)].ctype = rt; diff --git a/src/simulation/elements/ELEC.cpp b/src/simulation/elements/ELEC.cpp index 9874019e9..f759983c9 100644 --- a/src/simulation/elements/ELEC.cpp +++ b/src/simulation/elements/ELEC.cpp @@ -52,6 +52,8 @@ void Element::Element_ELEC() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto rx = -2; rx <= 2; rx++) { for (auto ry = -2; ry <= 2; ry++) @@ -118,7 +120,7 @@ static int update(UPDATE_FUNC_ARGS) case PT_NONE: //seems to speed up ELEC even if it isn't used break; default: - if ((sim->elements[rt].Properties & PROP_CONDUCTS) && (rt!=PT_NBLE||parts[i].temp<2273.15)) + if ((elements[rt].Properties & PROP_CONDUCTS) && (rt!=PT_NBLE||parts[i].temp<2273.15)) { sim->create_part(-1, x+rx, y+ry, PT_SPRK); sim->kill_part(i); diff --git a/src/simulation/elements/EMBR.cpp b/src/simulation/elements/EMBR.cpp index c94a1ad5d..70b2cba1e 100644 --- a/src/simulation/elements/EMBR.cpp +++ b/src/simulation/elements/EMBR.cpp @@ -52,6 +52,8 @@ void Element::Element_EMBR() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto rx = -1; rx <= 1; rx++) { for (auto ry = -1; ry <= 1; ry++) @@ -61,7 +63,7 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if (!r) continue; - if ((sim->elements[TYP(r)].Properties & (TYPE_SOLID | TYPE_PART | TYPE_LIQUID)) && !(sim->elements[TYP(r)].Properties & PROP_SPARKSETTLE)) + if ((elements[TYP(r)].Properties & (TYPE_SOLID | TYPE_PART | TYPE_LIQUID)) && !(elements[TYP(r)].Properties & PROP_SPARKSETTLE)) { sim->kill_part(i); return 1; diff --git a/src/simulation/elements/FIGH.cpp b/src/simulation/elements/FIGH.cpp index fc82caee3..6d32775d1 100644 --- a/src/simulation/elements/FIGH.cpp +++ b/src/simulation/elements/FIGH.cpp @@ -64,6 +64,8 @@ void Element::Element_FIGH() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (parts[i].tmp < 0 || parts[i].tmp >= MAX_FIGHTERS) { sim->kill_part(i); @@ -104,8 +106,8 @@ static int update(UPDATE_FUNC_ARGS) if ((pow(float(tarx-x), 2) + pow(float(tary-y), 2))<600) { if (figh->elem == PT_LIGH || figh->elem == PT_NEUT - || sim->elements[figh->elem].Properties & (PROP_DEADLY | PROP_RADIOACTIVE) - || sim->elements[figh->elem].DefaultProperties.temp >= 323 || sim->elements[figh->elem].DefaultProperties.temp <= 243) + || elements[figh->elem].Properties & (PROP_DEADLY | PROP_RADIOACTIVE) + || elements[figh->elem].DefaultProperties.temp >= 323 || elements[figh->elem].DefaultProperties.temp <= 243) figh->comm = (int)figh->comm | 0x08; } else if (tarx= 30.0f && (parts[i].temp > sim->elements[PT_ROCK].HighTemperature || pres < sim->elements[PT_ROCK].HighPressure)) // Form ROCK with pressure, if it will stay molten or not immediately break + else if ((parts[i].ctype == PT_STNE || !parts[i].ctype) && pres >= 30.0f && (parts[i].temp > elements[PT_ROCK].HighTemperature || pres < elements[PT_ROCK].HighPressure)) // Form ROCK with pressure, if it will stay molten or not immediately break { parts[i].tmp2 = sim->rng.between(0, 10); // Provide tmp2 for color noise parts[i].ctype = PT_ROCK; @@ -202,7 +204,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS) if (parts[i].ctype == PT_QRTZ && rt == PT_LAVA && parts[ID(r)].ctype == PT_CLST) { float pres = std::max(sim->pv[y/CELL][x/CELL]*10.0f, 0.0f); - if (parts[i].temp >= pres+sim->elements[PT_CRMC].HighTemperature+50.0f) + if (parts[i].temp >= pres+elements[PT_CRMC].HighTemperature+50.0f) { parts[i].ctype = PT_CRMC; parts[ID(r)].ctype = PT_CRMC; @@ -219,7 +221,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS) case 1: parts[i].ctype = PT_CLST; // avoid creating CRMC. - if (parts[i].temp >= sim->elements[PT_PQRT].HighTemperature * 3) + if (parts[i].temp >= elements[PT_PQRT].HighTemperature * 3) { parts[i].ctype = PT_PQRT; } @@ -241,7 +243,7 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS) } else if (rt == PT_HEAC && parts[i].ctype == PT_HEAC) { - if (parts[ID(r)].temp > sim->elements[PT_HEAC].HighTemperature) + if (parts[ID(r)].temp > elements[PT_HEAC].HighTemperature) { sim->part_change_type(ID(r), x+rx, y+ry, PT_LAVA); parts[ID(r)].ctype = PT_HEAC; @@ -260,18 +262,18 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS) } } - if ((surround_space || sim->elements[rt].Explosive) && - sim->elements[rt].Flammable && sim->rng.chance(int(sim->elements[rt].Flammable + (sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f)), 1000) && + if ((surround_space || elements[rt].Explosive) && + elements[rt].Flammable && sim->rng.chance(int(elements[rt].Flammable + (sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f)), 1000) && //exceptions, t is the thing causing the spark and rt is what's burning (t != PT_SPRK || (rt != PT_RBDM && rt != PT_LRBD && rt != PT_INSL)) && (t != PT_PHOT || rt != PT_INSL) && (rt != PT_SPNG || parts[ID(r)].life == 0)) { sim->part_change_type(ID(r), x+rx, y+ry, PT_FIRE); - parts[ID(r)].temp = restrict_flt(sim->elements[PT_FIRE].DefaultProperties.temp + (sim->elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP); + parts[ID(r)].temp = restrict_flt(elements[PT_FIRE].DefaultProperties.temp + (elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP); parts[ID(r)].life = sim->rng.between(180, 259); parts[ID(r)].tmp = parts[ID(r)].ctype = 0; - if (sim->elements[rt].Explosive) + if (elements[rt].Explosive) sim->pv[y/CELL][x/CELL] += 0.25f * CFDS; } } @@ -284,6 +286,8 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS) static int updateLegacy(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int t = parts[i].type; for (auto rx = -2; rx <= 2; rx++) { @@ -300,10 +304,10 @@ static int updateLegacy(UPDATE_FUNC_ARGS) auto lpv = (int)sim->pv[(y+ry)/CELL][(x+rx)/CELL]; if (lpv < 1) lpv = 1; - if (sim->elements[rt].Meltable && + if (elements[rt].Meltable && ((rt!=PT_RBDM && rt!=PT_LRBD) || t!=PT_SPRK) && ((t!=PT_FIRE&&t!=PT_PLSM) || (rt!=PT_METL && rt!=PT_IRON && rt!=PT_ETRD && rt!=PT_PSCN && rt!=PT_NSCN && rt!=PT_NTCT && rt!=PT_PTCT && rt!=PT_BMTL && rt!=PT_BRMT && rt!=PT_SALT && rt!=PT_INWR)) - && sim->rng.chance(sim->elements[rt].Meltable*lpv, 1000)) + && sim->rng.chance(elements[rt].Meltable*lpv, 1000)) { if (t!=PT_LAVA || parts[i].life>0) { diff --git a/src/simulation/elements/FIRW.cpp b/src/simulation/elements/FIRW.cpp index 8510a9f25..c09f67c7f 100644 --- a/src/simulation/elements/FIRW.cpp +++ b/src/simulation/elements/FIRW.cpp @@ -49,6 +49,8 @@ void Element::Element_FIRW() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (parts[i].tmp<=0) { for (auto rx = -1; rx <= 1; rx++) @@ -64,12 +66,12 @@ static int update(UPDATE_FUNC_ARGS) if (rt==PT_FIRE||rt==PT_PLSM||rt==PT_THDR) { float gx, gy, multiplier; - sim->GetGravityField(x, y, sim->elements[PT_FIRW].Gravity, 1.0f, gx, gy); + sim->GetGravityField(x, y, elements[PT_FIRW].Gravity, 1.0f, gx, gy); if (gx*gx+gy*gy < 0.001f) { float angle = sim->rng.between(0, 6283) * 0.001f;//(in radians, between 0 and 2*pi) - gx += sinf(angle)*sim->elements[PT_FIRW].Gravity*0.5f; - gy += cosf(angle)*sim->elements[PT_FIRW].Gravity*0.5f; + gx += sinf(angle)*elements[PT_FIRW].Gravity*0.5f; + gy += cosf(angle)*elements[PT_FIRW].Gravity*0.5f; } parts[i].tmp = 1; parts[i].life = sim->rng.between(20, 29); diff --git a/src/simulation/elements/FOG.cpp b/src/simulation/elements/FOG.cpp index 19765bdcd..830c0adfc 100644 --- a/src/simulation/elements/FOG.cpp +++ b/src/simulation/elements/FOG.cpp @@ -48,6 +48,8 @@ void Element::Element_FOG() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto rx = -1; rx <= 1; rx++) { for (auto ry = -1; ry <= 1; ry++) @@ -57,7 +59,7 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if (!r) continue; - if ((sim->elements[TYP(r)].Properties&TYPE_SOLID) && sim->rng.chance(1, 10) && parts[i].life==0 && !(TYP(r)==PT_CLNE || TYP(r)==PT_PCLN)) // TODO: should this also exclude BCLN? + if ((elements[TYP(r)].Properties&TYPE_SOLID) && sim->rng.chance(1, 10) && parts[i].life==0 && !(TYP(r)==PT_CLNE || TYP(r)==PT_PCLN)) // TODO: should this also exclude BCLN? { sim->part_change_type(i,x,y,PT_RIME); } diff --git a/src/simulation/elements/FRAY.cpp b/src/simulation/elements/FRAY.cpp index 286e28755..df011d61a 100644 --- a/src/simulation/elements/FRAY.cpp +++ b/src/simulation/elements/FRAY.cpp @@ -48,6 +48,8 @@ void Element::Element_FRAY() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int curlen; if (parts[i].tmp > 0) curlen = parts[i].tmp; @@ -73,7 +75,7 @@ static int update(UPDATE_FUNC_ARGS) r = pmap[y+nyi+nyy][x+nxi+nxx]; if (!r) r = sim->photons[y+nyi+nyy][x+nxi+nxx]; - if (r && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)){ + if (r && !(elements[TYP(r)].Properties & TYPE_SOLID)){ parts[ID(r)].vx += nxi*((parts[i].temp-273.15f)/10.0f); parts[ID(r)].vy += nyi*((parts[i].temp-273.15f)/10.0f); } diff --git a/src/simulation/elements/FWRK.cpp b/src/simulation/elements/FWRK.cpp index 4a6f5ef69..236e9b5e2 100644 --- a/src/simulation/elements/FWRK.cpp +++ b/src/simulation/elements/FWRK.cpp @@ -48,16 +48,18 @@ void Element::Element_FWRK() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (parts[i].life == 0 && ((surround_space && parts[i].temp>400 && sim->rng.chance(int(9+parts[i].temp/40), 100000)) || parts[i].ctype == PT_DUST)) { float gx, gy, multiplier, gmax; int randTmp; - sim->GetGravityField(x, y, sim->elements[PT_FWRK].Gravity, 1.0f, gx, gy); + sim->GetGravityField(x, y, elements[PT_FWRK].Gravity, 1.0f, gx, gy); if (gx*gx+gy*gy < 0.001f) { float angle = sim->rng.between(0, 6283) * 0.001f;//(in radians, between 0 and 2*pi) - gx += sinf(angle)*sim->elements[PT_FWRK].Gravity*0.5f; - gy += cosf(angle)*sim->elements[PT_FWRK].Gravity*0.5f; + gx += sinf(angle)*elements[PT_FWRK].Gravity*0.5f; + gy += cosf(angle)*elements[PT_FWRK].Gravity*0.5f; } gmax = std::max(fabsf(gx), fabsf(gy)); if (sim->eval_move(PT_FWRK, (int)(x-(gx/gmax)+0.5f), (int)(y-(gy/gmax)+0.5f), NULL)) diff --git a/src/simulation/elements/GEL.cpp b/src/simulation/elements/GEL.cpp index 7da0abfbe..b1fed66b3 100644 --- a/src/simulation/elements/GEL.cpp +++ b/src/simulation/elements/GEL.cpp @@ -50,6 +50,8 @@ void Element::Element_GEL() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (parts[i].tmp > 100) parts[i].tmp = 100; if (parts[i].tmp < 0) @@ -133,17 +135,17 @@ static int update(UPDATE_FUNC_ARGS) dy = parts[i].y - parts[ID(r)].y; //Stickiness - if ((dx*dx + dy*dy)>1.5 && (gel || !sim->elements[rt].Falldown || (fabs((float)rx)<2 && fabs((float)ry)<2))) + if ((dx*dx + dy*dy)>1.5 && (gel || !elements[rt].Falldown || (fabs((float)rx)<2 && fabs((float)ry)<2))) { float per, nd; nd = dx*dx + dy*dy - 0.5; per = 5*(1 - parts[i].tmp/100)*(nd/(dx*dx + dy*dy + nd) - 0.5); - if (sim->elements[rt].Properties&TYPE_LIQUID) + if (elements[rt].Properties&TYPE_LIQUID) per *= 0.1f; dx *= per; dy *= per; parts[i].vx += dx; parts[i].vy += dy; - if ((sim->elements[rt].Properties&TYPE_PART) || rt==PT_GOO) + if ((elements[rt].Properties&TYPE_PART) || rt==PT_GOO) { parts[ID(r)].vx -= dx; parts[ID(r)].vy -= dy; diff --git a/src/simulation/elements/H2.cpp b/src/simulation/elements/H2.cpp index ccb0ae299..c7cedc4c6 100644 --- a/src/simulation/elements/H2.cpp +++ b/src/simulation/elements/H2.cpp @@ -47,6 +47,8 @@ void Element::Element_H2() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; for (auto rx = -2; rx <= 2; rx++) { for (auto ry = -2; ry <= 2; ry++) @@ -119,7 +121,7 @@ static int update(UPDATE_FUNC_ARGS) parts[j].tmp = 0x1; } auto rx = x + sim->rng.between(-1, 1), ry = y + sim->rng.between(-1, 1), rt = TYP(pmap[ry][rx]); - if (sim->can_move[PT_PLSM][rt] || rt == PT_H2) + if (can_move[PT_PLSM][rt] || rt == PT_H2) { j = sim->create_part(-3,rx,ry,PT_PLSM); if (j>-1) diff --git a/src/simulation/elements/HEAC.cpp b/src/simulation/elements/HEAC.cpp index 9fdb10928..7d06e18d1 100644 --- a/src/simulation/elements/HEAC.cpp +++ b/src/simulation/elements/HEAC.cpp @@ -48,7 +48,8 @@ void Element::Element_HEAC() } static const auto isInsulator = [](Simulation* a, int b) -> bool { - return b && (a->elements[TYP(b)].HeatConduct == 0 || (TYP(b) == PT_HSWC && a->parts[ID(b)].life != 10)); + auto &sd = SimulationData::CRef(); + return b && (sd.elements[TYP(b)].HeatConduct == 0 || (TYP(b) == PT_HSWC && a->parts[ID(b)].life != 10)); }; // If this is used elsewhere (GOLD), it should be moved into Simulation.h @@ -118,6 +119,8 @@ bool CheckLine(Simulation* sim, int x1, int y1, int x2, int y2, BinaryPredicate static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; const int rad = 4; int rry, rrx, r, count = 0; float tempAgg = 0; @@ -130,13 +133,13 @@ static int update(UPDATE_FUNC_ARGS) if (x+rrx >= 0 && x+rrx < XRES && y+rry >= 0 && y+rry < YRES && !CheckLine(sim, x, y, x+rrx, y+rry, isInsulator)) { r = pmap[y+rry][x+rrx]; - if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) + if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) { count++; tempAgg += parts[ID(r)].temp; } r = sim->photons[y+rry][x+rrx]; - if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) + if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) { count++; tempAgg += parts[ID(r)].temp; @@ -158,12 +161,12 @@ static int update(UPDATE_FUNC_ARGS) if (x+rrx >= 0 && x+rrx < XRES && y+rry >= 0 && y+rry < YRES && !CheckLine(sim, x, y, x+rrx, y+rry, isInsulator)) { r = pmap[y+rry][x+rrx]; - if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) + if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) { parts[ID(r)].temp = parts[i].temp; } r = sim->photons[y+rry][x+rrx]; - if (r && sim->elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) + if (r && elements[TYP(r)].HeatConduct > 0 && (TYP(r) != PT_HSWC || parts[ID(r)].life == 10)) { parts[ID(r)].temp = parts[i].temp; } diff --git a/src/simulation/elements/ICEI.cpp b/src/simulation/elements/ICEI.cpp index 3f93528df..db533fb9f 100644 --- a/src/simulation/elements/ICEI.cpp +++ b/src/simulation/elements/ICEI.cpp @@ -50,6 +50,8 @@ void Element::Element_ICEI() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (parts[i].ctype==PT_FRZW)//get colder if it is from FRZW { parts[i].temp = restrict_flt(parts[i].temp-1.0f, MIN_TEMP, MAX_TEMP); @@ -65,7 +67,7 @@ static int update(UPDATE_FUNC_ARGS) continue; if (TYP(r)==PT_SALT || TYP(r)==PT_SLTW) { - if (parts[i].temp > sim->elements[PT_SLTW].LowTemperature && sim->rng.chance(1, 200)) + if (parts[i].temp > elements[PT_SLTW].LowTemperature && sim->rng.chance(1, 200)) { sim->part_change_type(i,x,y,PT_SLTW); sim->part_change_type(ID(r),x+rx,y+ry,PT_SLTW); diff --git a/src/simulation/elements/LDTC.cpp b/src/simulation/elements/LDTC.cpp index 0020cc8ad..850f57635 100644 --- a/src/simulation/elements/LDTC.cpp +++ b/src/simulation/elements/LDTC.cpp @@ -74,8 +74,10 @@ static bool phot_data_type(int rt) */ static bool accepted_conductor(Simulation* sim, int r) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rt = TYP(r); - return (sim->elements[rt].Properties & PROP_CONDUCTS) && + return (elements[rt].Properties & PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && sim->parts[ID(r)].life == 0; diff --git a/src/simulation/elements/LIFE.cpp b/src/simulation/elements/LIFE.cpp index 184df2f44..fda53089a 100644 --- a/src/simulation/elements/LIFE.cpp +++ b/src/simulation/elements/LIFE.cpp @@ -50,6 +50,7 @@ void Element::Element_LIFE() static int graphics(GRAPHICS_FUNC_ARGS) { + auto &builtinGol = SimulationData::builtinGol; auto colour1 = RGB::Unpack(cpart->dcolour); auto colour2 = RGB::Unpack(cpart->tmp); if (!cpart->dcolour) @@ -91,6 +92,8 @@ static int graphics(GRAPHICS_FUNC_ARGS) static void create(ELEMENT_CREATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &builtinGol = sd.builtinGol; if (v == -1) v = 0; // * 0x200000: No need to look for colours, they'll be set later anyway. @@ -105,7 +108,7 @@ static void create(ELEMENT_CREATE_FUNC_ARGS) } else if (!skipLookup) { - auto *cgol = sim->GetCustomGOLByRule(v); + auto *cgol = sd.GetCustomGOLByRule(v); if (cgol) { sim->parts[i].dcolour = cgol->colour1; diff --git a/src/simulation/elements/LIGH.cpp b/src/simulation/elements/LIGH.cpp index 92380b43e..4743c1814 100644 --- a/src/simulation/elements/LIGH.cpp +++ b/src/simulation/elements/LIGH.cpp @@ -79,6 +79,8 @@ static int update(UPDATE_FUNC_ARGS) sim->hv[y/CELL][x/CELL] = MAX_TEMP; } + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; for (auto rx = -2; rx <= 2; rx++) { for (auto ry = -2; ry <= 2; ry++) @@ -89,15 +91,15 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; auto rt = TYP(r); - if ((surround_space || sim->elements[rt].Explosive) && + if ((surround_space || elements[rt].Explosive) && (rt!=PT_SPNG || parts[ID(r)].life==0) && - sim->elements[rt].Flammable && sim->rng.chance(sim->elements[rt].Flammable + int(sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f), 1000)) + elements[rt].Flammable && sim->rng.chance(elements[rt].Flammable + int(sim->pv[(y+ry)/CELL][(x+rx)/CELL] * 10.0f), 1000)) { sim->part_change_type(ID(r),x+rx,y+ry,PT_FIRE); - parts[ID(r)].temp = restrict_flt(sim->elements[PT_FIRE].DefaultProperties.temp + (sim->elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP); + parts[ID(r)].temp = restrict_flt(elements[PT_FIRE].DefaultProperties.temp + (elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP); parts[ID(r)].life = sim->rng.between(180, 259); parts[ID(r)].tmp = parts[ID(r)].ctype = 0; - if (sim->elements[rt].Explosive) + if (elements[rt].Explosive) sim->pv[y/CELL][x/CELL] += 0.25f * CFDS; } switch (rt) @@ -138,7 +140,7 @@ static int update(UPDATE_FUNC_ARGS) break; case PT_HEAC: parts[ID(r)].temp = restrict_flt(parts[ID(r)].temp+powderful/10, MIN_TEMP, MAX_TEMP); - if (parts[ID(r)].temp > sim->elements[PT_HEAC].HighTemperature) + if (parts[ID(r)].temp > elements[PT_HEAC].HighTemperature) { sim->part_change_type(ID(r), x+rx, y+ry, PT_LAVA); parts[ID(r)].ctype = PT_HEAC; @@ -147,10 +149,10 @@ static int update(UPDATE_FUNC_ARGS) default: break; } - if ((sim->elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0) + if ((elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0) sim->create_part(ID(r),x+rx,y+ry,PT_SPRK); sim->pv[y/CELL][x/CELL] += powderful/400; - if (sim->elements[TYP(r)].HeatConduct) parts[ID(r)].temp = restrict_flt(parts[ID(r)].temp+powderful/1.3, MIN_TEMP, MAX_TEMP); + if (elements[TYP(r)].HeatConduct) parts[ID(r)].temp = restrict_flt(parts[ID(r)].temp+powderful/1.3, MIN_TEMP, MAX_TEMP); } } } diff --git a/src/simulation/elements/LSNS.cpp b/src/simulation/elements/LSNS.cpp index a70f4a22e..a5f933fe0 100644 --- a/src/simulation/elements/LSNS.cpp +++ b/src/simulation/elements/LSNS.cpp @@ -50,6 +50,8 @@ void Element::Element_LSNS() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rd = parts[i].tmp2; if (rd > 25) parts[i].tmp2 = rd = 25; if (parts[i].life) @@ -69,7 +71,7 @@ static int update(UPDATE_FUNC_ARGS) int rt = TYP(r); if (sim->parts_avg(i, ID(r), PT_INSL) != PT_INSL) { - if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) + if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) { parts[ID(r)].life = 4; parts[ID(r)].ctype = rt; diff --git a/src/simulation/elements/NBLE.cpp b/src/simulation/elements/NBLE.cpp index e2b9daffe..52ec8017f 100644 --- a/src/simulation/elements/NBLE.cpp +++ b/src/simulation/elements/NBLE.cpp @@ -49,6 +49,8 @@ void Element::Element_NBLE() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; if (parts[i].temp > 5273.15 && sim->pv[y/CELL][x/CELL] > 100.0f) { parts[i].tmp |= 0x1; @@ -75,7 +77,7 @@ static int update(UPDATE_FUNC_ARGS) parts[j].tmp = 0x1; } int rx = x + sim->rng.between(-1, 1), ry = y + sim->rng.between(-1, 1), rt = TYP(pmap[ry][rx]); - if (sim->can_move[PT_PLSM][rt] || rt == PT_NBLE) + if (can_move[PT_PLSM][rt] || rt == PT_NBLE) { j = sim->create_part(-3,rx,ry,PT_PLSM); if (j != -1) diff --git a/src/simulation/elements/O2.cpp b/src/simulation/elements/O2.cpp index bba9c936f..06747486d 100644 --- a/src/simulation/elements/O2.cpp +++ b/src/simulation/elements/O2.cpp @@ -47,6 +47,8 @@ void Element::Element_O2() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &can_move = sd.can_move; for (auto rx = -2; rx <= 2; rx++) { for (auto ry = -2; ry <= 2; ry++) @@ -99,7 +101,7 @@ static int update(UPDATE_FUNC_ARGS) parts[j].tmp = 0x1; } auto rx = x + sim->rng.between(-1, 1), ry = y + sim->rng.between(-1, 1), r = TYP(pmap[ry][rx]); - if (sim->can_move[PT_PLSM][r] || r == PT_O2) + if (can_move[PT_PLSM][r] || r == PT_O2) { j = sim->create_part(-3,rx,ry,PT_PLSM); if (j > -1) diff --git a/src/simulation/elements/PBCN.cpp b/src/simulation/elements/PBCN.cpp index e2b678d52..d749c0531 100644 --- a/src/simulation/elements/PBCN.cpp +++ b/src/simulation/elements/PBCN.cpp @@ -54,6 +54,8 @@ constexpr float ADVECTION = 0.1f; static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!parts[i].tmp2 && sim->pv[y/CELL][x/CELL]>4.0f) parts[i].tmp2 = sim->rng.between(80, 119); if (parts[i].tmp2) @@ -66,7 +68,7 @@ static int update(UPDATE_FUNC_ARGS) return 1; } } - if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled) + if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !elements[parts[i].ctype].Enabled) { for (auto rx = -1; rx <= 1; rx++) { @@ -117,7 +119,7 @@ static int update(UPDATE_FUNC_ARGS) } } } - if (parts[i].ctype>0 && parts[i].ctypeelements[parts[i].ctype].Enabled) + if (parts[i].ctype>0 && parts[i].ctypecreate_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype)); if (np>-1) { - if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp0 && parts[i].life!=10) parts[i].life--; for (auto rx = -2; rx <= 2; rx++) @@ -83,7 +85,7 @@ static int update(UPDATE_FUNC_ARGS) } } } - if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled) + if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !elements[parts[i].ctype].Enabled) { for (auto rx = -1; rx <= 1; rx++) { @@ -108,7 +110,7 @@ static int update(UPDATE_FUNC_ARGS) } } } - if (parts[i].ctype>0 && parts[i].ctypeelements[parts[i].ctype].Enabled && parts[i].life==10) + if (parts[i].ctype>0 && parts[i].ctypecreate_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), TYP(parts[i].ctype)); if (np>=0) { - if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpelements[parts[i].tmp].HighTemperatureTransition==PT_LAVA) + if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmpelements[TYP(parts[i].ctype)].Enabled) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (parts[i].ctype && !elements[TYP(parts[i].ctype)].Enabled) parts[i].ctype = 0; if (parts[i].tmp & PPIP_TMPFLAG_TRIGGERS) { @@ -259,14 +261,14 @@ int Element_PIPE_update(UPDATE_FUNC_ARGS) } } //try eating particle at entrance - else if (!TYP(parts[i].ctype) && (sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) + else if (!TYP(parts[i].ctype) && (elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) { if (TYP(r)==PT_SOAP) Element_SOAP_detach(sim, ID(r)); transfer_part_to_pipe(parts+(ID(r)), parts+i); sim->kill_part(ID(r)); } - else if (!TYP(parts[i].ctype) && TYP(r)==PT_STOR && sim->IsElement(parts[ID(r)].tmp) && (sim->elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) + else if (!TYP(parts[i].ctype) && TYP(r)==PT_STOR && sd.IsElement(parts[ID(r)].tmp) && (elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) { // STOR stores properties in the same places as PIPE does transfer_pipe_to_pipe(parts+(ID(r)), parts+i, true); @@ -344,8 +346,10 @@ int Element_PIPE_update(UPDATE_FUNC_ARGS) int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int t = TYP(cpart->ctype); - if (t>0 && tsim->elements[t].Enabled) + if (t>0 && ttmp = tpart.tmp3; cpart->ctype = tpart.tmp4; - RGB colour = ren->sim->elements[t].Colour; + RGB colour = elements[t].Colour; *colr = colour.Red; *colg = colour.Green; *colb = colour.Blue; - if (ren->sim->elements[t].Graphics) + if (elements[t].Graphics) { - (*(ren->sim->elements[t].Graphics))(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); + (*(elements[t].Graphics))(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); } else { @@ -419,6 +423,8 @@ int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; // STOR also calls this function to move particles from STOR to PRTI // PIPE was changed, so now PIPE and STOR don't use the same particle storage format if (STOR) @@ -436,7 +442,7 @@ void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Partic part->tmp = pipe->tmp3; part->ctype = pipe->tmp4; - if (!(sim->elements[part->type].Properties & TYPE_ENERGY)) + if (!(elements[part->type].Properties & TYPE_ENERGY)) { part->vx = 0.0f; part->vy = 0.0f; diff --git a/src/simulation/elements/PROT.cpp b/src/simulation/elements/PROT.cpp index 5d0c7a2a3..6dfa398c9 100644 --- a/src/simulation/elements/PROT.cpp +++ b/src/simulation/elements/PROT.cpp @@ -54,6 +54,8 @@ void Element::Element_PROT() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; sim->pv[y/CELL][x/CELL] -= .003f; int under = pmap[y][x]; int utype = TYP(under); @@ -111,14 +113,14 @@ static int update(UPDATE_FUNC_ARGS) break; default: //set off explosives (only when hot because it wasn't as fun when it made an entire save explode) - if (parts[i].temp > 273.15f + 500.0f && (sim->elements[utype].Flammable || sim->elements[utype].Explosive || utype == PT_BANG)) + if (parts[i].temp > 273.15f + 500.0f && (elements[utype].Flammable || elements[utype].Explosive || utype == PT_BANG)) { sim->create_part(uID, x, y, PT_FIRE); - parts[uID].temp += restrict_flt(float(sim->elements[utype].Flammable * 5), MIN_TEMP, MAX_TEMP); + parts[uID].temp += restrict_flt(float(elements[utype].Flammable * 5), MIN_TEMP, MAX_TEMP); sim->pv[y / CELL][x / CELL] += 1.00f; } //prevent inactive sparkable elements from being sparked - else if ((sim->elements[utype].Properties&PROP_CONDUCTS) && parts[uID].life <= 4) + else if ((elements[utype].Properties&PROP_CONDUCTS) && parts[uID].life <= 4) { parts[uID].life = 40 + parts[uID].life; } diff --git a/src/simulation/elements/PRTI.cpp b/src/simulation/elements/PRTI.cpp index c0675eed5..53869e43e 100644 --- a/src/simulation/elements/PRTI.cpp +++ b/src/simulation/elements/PRTI.cpp @@ -59,6 +59,8 @@ void Element::Element_PRTI() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int fe = 0; parts[i].tmp = (int)((parts[i].temp-73.15f)/100+1); @@ -76,7 +78,7 @@ static int update(UPDATE_FUNC_ARGS) int r = pmap[y+ry][x+rx]; if (!r || TYP(r) == PT_STOR) fe = 1; - if (!r || (!(sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) && TYP(r)!=PT_SPRK && TYP(r)!=PT_STOR)) + if (!r || (!(elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) && TYP(r)!=PT_SPRK && TYP(r)!=PT_STOR)) { r = sim->photons[y+ry][x+rx]; if (!r) @@ -94,7 +96,7 @@ static int update(UPDATE_FUNC_ARGS) { if (TYP(r) == PT_STOR) { - if (sim->IsElement(parts[ID(r)].tmp) && (sim->elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) + if (sd.IsElement(parts[ID(r)].tmp) && (elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))) { // STOR uses same format as PIPE, so we can use this function to do the transfer Element_PIPE_transfer_pipe_to_part(sim, parts+(ID(r)), &sim->portalp[parts[i].tmp][count][nnx], true); diff --git a/src/simulation/elements/PSNS.cpp b/src/simulation/elements/PSNS.cpp index 3d893f287..221efbef8 100644 --- a/src/simulation/elements/PSNS.cpp +++ b/src/simulation/elements/PSNS.cpp @@ -48,6 +48,8 @@ void Element::Element_PSNS() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if ((parts[i].tmp == 0 && sim->pv[y/CELL][x/CELL] > parts[i].temp-273.15f) || (parts[i].tmp == 2 && sim->pv[y/CELL][x/CELL] < parts[i].temp-273.15f)) { for (auto rx = -2; rx <= 2; rx++) @@ -62,7 +64,7 @@ static int update(UPDATE_FUNC_ARGS) if (sim->parts_avg(i,ID(r),PT_INSL) != PT_INSL) { auto rt = TYP(r); - if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) + if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[ID(r)].life==0) { parts[ID(r)].life = 4; parts[ID(r)].ctype = rt; diff --git a/src/simulation/elements/RPEL.cpp b/src/simulation/elements/RPEL.cpp index 0bde82704..44232165b 100644 --- a/src/simulation/elements/RPEL.cpp +++ b/src/simulation/elements/RPEL.cpp @@ -49,6 +49,8 @@ void Element::Element_RPEL() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int r, rx, ry, ri; for(ri = 0; ri <= 10; ri++) { @@ -60,7 +62,7 @@ static int update(UPDATE_FUNC_ARGS) if (!r) r = sim->photons[y+ry][x+rx]; - if (r && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)) { + if (r && !(elements[TYP(r)].Properties & TYPE_SOLID)) { if (!parts[i].ctype || parts[i].ctype == parts[ID(r)].type) { parts[ID(r)].vx += isign(rx)*((parts[i].temp-273.15)/10.0f); parts[ID(r)].vy += isign(ry)*((parts[i].temp-273.15)/10.0f); diff --git a/src/simulation/elements/SOAP.cpp b/src/simulation/elements/SOAP.cpp index 1c335c540..0cf43ff60 100644 --- a/src/simulation/elements/SOAP.cpp +++ b/src/simulation/elements/SOAP.cpp @@ -99,6 +99,8 @@ static int update(UPDATE_FUNC_ARGS) //0x02 - first mate yes/no //0x04 - "back" mate yes/no + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (parts[i].ctype&1) { // reset invalid SOAP links @@ -171,7 +173,7 @@ static int update(UPDATE_FUNC_ARGS) if (parts[i].temp>FREEZING) { if (sim->bmap[(y+ry)/CELL][(x+rx)/CELL] - || (r && !(sim->elements[TYP(r)].Properties&TYPE_GAS) + || (r && !(elements[TYP(r)].Properties&TYPE_GAS) && TYP(r) != PT_SOAP && TYP(r) != PT_GLAS)) { Element_SOAP_detach(sim, i); diff --git a/src/simulation/elements/SPRK.cpp b/src/simulation/elements/SPRK.cpp index 4b43a5869..3d2381422 100644 --- a/src/simulation/elements/SPRK.cpp +++ b/src/simulation/elements/SPRK.cpp @@ -52,6 +52,8 @@ void Element::Element_SPRK() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int ct = parts[i].ctype; Element_FIRE_update(UPDATE_FUNC_SUBCALL_ARGS); @@ -59,7 +61,7 @@ static int update(UPDATE_FUNC_ARGS) { if (ct==PT_WATR||ct==PT_SLTW||ct==PT_PSCN||ct==PT_NSCN||ct==PT_ETRD||ct==PT_INWR) parts[i].temp = R_TEMP + 273.15f; - if (ct<=0 || ct>=PT_NUM || !sim->elements[parts[i].ctype].Enabled) + if (ct<=0 || ct>=PT_NUM || !elements[parts[i].ctype].Enabled) ct = PT_METL; parts[i].ctype = PT_NONE; parts[i].life = 4; @@ -271,7 +273,7 @@ static int update(UPDATE_FUNC_ARGS) } if (pavg == PT_INSL) continue; //Insulation blocks everything past here - if (!((sim->elements[receiver].Properties&PROP_CONDUCTS)||receiver==PT_INST||receiver==PT_QRTZ)) continue; //Stop non-conducting receivers, allow INST and QRTZ as special cases + if (!((elements[receiver].Properties&PROP_CONDUCTS)||receiver==PT_INST||receiver==PT_QRTZ)) continue; //Stop non-conducting receivers, allow INST and QRTZ as special cases if (abs(rx)+abs(ry)>=4 &&sender!=PT_SWCH&&receiver!=PT_SWCH) continue; //Only switch conducts really far if (receiver==sender && receiver!=PT_INST && receiver!=PT_QRTZ) goto conduct; //Everything conducts to itself, except INST. diff --git a/src/simulation/elements/STKM.cpp b/src/simulation/elements/STKM.cpp index 78455a74c..79f79a786 100644 --- a/src/simulation/elements/STKM.cpp +++ b/src/simulation/elements/STKM.cpp @@ -114,6 +114,8 @@ void die(Simulation *sim, playerst *playerp, int i) int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int r, rx, ry; int t = parts[i].type; float pp, d; @@ -125,7 +127,7 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) float rocketBootsHeadEffectV = 0.3f;// stronger acceleration vertically, to counteract gravity float rocketBootsFeetEffectV = 0.45f; - if (!playerp->fan && parts[i].ctype && sim->IsElementOrNone(parts[i].ctype)) + if (!playerp->fan && parts[i].ctype && sd.IsElementOrNone(parts[i].ctype)) Element_STKM_set_element(sim, playerp, parts[i].ctype); playerp->frames++; @@ -449,7 +451,7 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) { ry -= 2 * sim->rng.between(0, 1) + 1; r = pmap[ry][rx]; - if (sim->elements[TYP(r)].Properties&TYPE_SOLID) + if (elements[TYP(r)].Properties&TYPE_SOLID) { sim->create_part(-1, rx, ry, PT_SPRK); playerp->frames = 0; @@ -520,7 +522,7 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) { parts[np].vx -= -mvy*(5*((((int)playerp->pcomm)&0x02) == 0x02) - 5*(((int)(playerp->pcomm)&0x01) == 0x01)); parts[np].vy -= mvx*(5*((((int)playerp->pcomm)&0x02) == 0x02) - 5*(((int)(playerp->pcomm)&0x01) == 0x01)); - parts[i].vx -= (sim->elements[(int)playerp->elem].Weight*parts[np].vx)/1000; + parts[i].vx -= (elements[(int)playerp->elem].Weight*parts[np].vx)/1000; } playerp->frames = 0; } @@ -627,6 +629,8 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS) void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int y) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int r; if (x<0 || y<0 || x>=XRES || y>=YRES || !sim->parts[i].type) return; @@ -639,13 +643,13 @@ void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int damage += sim->rng.between(32, 51); } - if (sim->elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||sim->parts[ID(r)].life==10) && ((playerp->elem!=PT_LIGH && sim->parts[ID(r)].temp>=323) || sim->parts[ID(r)].temp<=243) && (!playerp->rocketBoots || TYP(r)!=PT_PLSM)) + if (elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||sim->parts[ID(r)].life==10) && ((playerp->elem!=PT_LIGH && sim->parts[ID(r)].temp>=323) || sim->parts[ID(r)].temp<=243) && (!playerp->rocketBoots || TYP(r)!=PT_PLSM)) { damage += 2; playerp->accs[3] -= 1; } - if (sim->elements[TYP(r)].Properties&PROP_DEADLY) + if (elements[TYP(r)].Properties&PROP_DEADLY) switch (TYP(r)) { case PT_ACID: @@ -656,7 +660,7 @@ void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int break; } - if (sim->elements[TYP(r)].Properties&PROP_RADIOACTIVE) + if (elements[TYP(r)].Properties&PROP_RADIOACTIVE) damage++; if (damage) @@ -741,10 +745,12 @@ void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i) void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element) { - if (sim->elements[element].Falldown != 0 - || sim->elements[element].Properties&TYPE_GAS - || sim->elements[element].Properties&TYPE_LIQUID - || sim->elements[element].Properties&TYPE_ENERGY + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (elements[element].Falldown != 0 + || elements[element].Properties&TYPE_GAS + || elements[element].Properties&TYPE_LIQUID + || elements[element].Properties&TYPE_ENERGY || element == PT_LOLZ || element == PT_LOVE) { if (!playerp->rocketBoots || element != PT_PLSM) diff --git a/src/simulation/elements/STOR.cpp b/src/simulation/elements/STOR.cpp index d0af46772..b2b09b475 100644 --- a/src/simulation/elements/STOR.cpp +++ b/src/simulation/elements/STOR.cpp @@ -53,7 +53,9 @@ void Element::Element_STOR() static int update(UPDATE_FUNC_ARGS) { - if (!sim->IsElementOrNone(parts[i].tmp)) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (!sd.IsElementOrNone(parts[i].tmp)) parts[i].tmp = 0; if(parts[i].life && !parts[i].tmp) parts[i].life--; @@ -66,7 +68,7 @@ static int update(UPDATE_FUNC_ARGS) auto r = pmap[y+ry][x+rx]; if ((ID(r))>=NPART || !r) continue; - if (!parts[i].tmp && !parts[i].life && TYP(r)!=PT_STOR && !(sim->elements[TYP(r)].Properties&TYPE_SOLID) && (!parts[i].ctype || TYP(r)==parts[i].ctype)) + if (!parts[i].tmp && !parts[i].life && TYP(r)!=PT_STOR && !(elements[TYP(r)].Properties&TYPE_SOLID) && (!parts[i].ctype || TYP(r)==parts[i].ctype)) { if (TYP(r) == PT_SOAP) Element_SOAP_detach(sim, ID(r)); @@ -120,7 +122,9 @@ static int graphics(GRAPHICS_FUNC_ARGS) static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS) { - if (sim->elements[t].Properties & TYPE_SOLID) + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if (elements[t].Properties & TYPE_SOLID) { return false; } diff --git a/src/simulation/elements/THDR.cpp b/src/simulation/elements/THDR.cpp index c22e7a474..ce3dc1cbd 100644 --- a/src/simulation/elements/THDR.cpp +++ b/src/simulation/elements/THDR.cpp @@ -50,6 +50,8 @@ void Element::Element_THDR() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; bool kill=false; for (auto rx = -2; rx <= 2; rx++) { @@ -61,7 +63,7 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; auto rt = TYP(r); - if ((sim->elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0 && !(rt==PT_WATR||rt==PT_SLTW) && parts[ID(r)].ctype!=PT_SPRK) + if ((elements[TYP(r)].Properties&PROP_CONDUCTS) && parts[ID(r)].life==0 && !(rt==PT_WATR||rt==PT_SLTW) && parts[ID(r)].ctype!=PT_SPRK) { parts[ID(r)].ctype = parts[ID(r)].type; sim->part_change_type(ID(r),x+rx,y+ry,PT_SPRK); diff --git a/src/simulation/elements/TRON.cpp b/src/simulation/elements/TRON.cpp index 4c9c7a24f..b818d25fa 100644 --- a/src/simulation/elements/TRON.cpp +++ b/src/simulation/elements/TRON.cpp @@ -270,9 +270,11 @@ static int trymovetron(Simulation * sim, int x, int y, int dir, int i, int len) static bool canmovetron(Simulation * sim, int r, int len) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; if (!r || (TYP(r) == PT_SWCH && sim->parts[ID(r)].life >= 10) || (TYP(r) == PT_INVIS && sim->parts[ID(r)].tmp2 == 1)) return true; - if ((((sim->elements[TYP(r)].Properties & PROP_LIFE_KILL_DEC) && sim->parts[ID(r)].life > 0)|| ((sim->elements[TYP(r)].Properties & PROP_LIFE_KILL) && (sim->elements[TYP(r)].Properties & PROP_LIFE_DEC))) && sim->parts[ID(r)].life < len) + if ((((elements[TYP(r)].Properties & PROP_LIFE_KILL_DEC) && sim->parts[ID(r)].life > 0)|| ((elements[TYP(r)].Properties & PROP_LIFE_KILL) && (elements[TYP(r)].Properties & PROP_LIFE_DEC))) && sim->parts[ID(r)].life < len) return true; return false; } diff --git a/src/simulation/elements/TSNS.cpp b/src/simulation/elements/TSNS.cpp index 7da107e06..3bb981d32 100644 --- a/src/simulation/elements/TSNS.cpp +++ b/src/simulation/elements/TSNS.cpp @@ -49,6 +49,8 @@ void Element::Element_TSNS() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rd = parts[i].tmp2; if (rd > 25) parts[i].tmp2 = rd = 25; @@ -69,7 +71,7 @@ static int update(UPDATE_FUNC_ARGS) int rt = TYP(r); if (sim->parts_avg(i, ID(r), PT_INSL) != PT_INSL) { - if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) + if ((elements[rt].Properties&PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) { parts[ID(r)].life = 4; parts[ID(r)].ctype = rt; diff --git a/src/simulation/elements/TUNG.cpp b/src/simulation/elements/TUNG.cpp index 086359a1d..4e5a22bd6 100644 --- a/src/simulation/elements/TUNG.cpp +++ b/src/simulation/elements/TUNG.cpp @@ -52,8 +52,10 @@ void Element::Element_TUNG() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; bool splode = false; - const float MELTING_POINT = sim->elements[PT_TUNG].HighTemperature; + const float MELTING_POINT = elements[PT_TUNG].HighTemperature; if(parts[i].temp > 2400.0) { @@ -112,7 +114,9 @@ static int update(UPDATE_FUNC_ARGS) static int graphics(GRAPHICS_FUNC_ARGS) { - const float MELTING_POINT = ren->sim->elements[PT_TUNG].HighTemperature; + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + const float MELTING_POINT = elements[PT_TUNG].HighTemperature; double startTemp = (MELTING_POINT - 1500.0); double tempOver = (((cpart->temp - startTemp)/1500.0)*TPT_PI_FLT) - (TPT_PI_FLT/2.0); if(tempOver > -(TPT_PI_FLT/2.0)) diff --git a/src/simulation/elements/VIBR.cpp b/src/simulation/elements/VIBR.cpp index fbb6a6c96..c4005da1b 100644 --- a/src/simulation/elements/VIBR.cpp +++ b/src/simulation/elements/VIBR.cpp @@ -50,6 +50,8 @@ void Element::Element_VIBR() int Element_VIBR_update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rndstore = 0; if (!parts[i].life) //if not exploding { @@ -89,7 +91,7 @@ int Element_VIBR_update(UPDATE_FUNC_ARGS) auto ry = (rndstore>>2)%3-1; rndstore = rndstore >> 4; auto r = pmap[y+ry][x+rx]; - if (TYP(r) && TYP(r) != PT_BREC && (sim->elements[TYP(r)].Properties&PROP_CONDUCTS) && !parts[ID(r)].life) + if (TYP(r) && TYP(r) != PT_BREC && (elements[TYP(r)].Properties&PROP_CONDUCTS) && !parts[ID(r)].life) { parts[ID(r)].life = 4; parts[ID(r)].ctype = TYP(r); @@ -102,7 +104,7 @@ int Element_VIBR_update(UPDATE_FUNC_ARGS) auto rx = rndstore%7-3; auto ry = (rndstore>>3)%7-3; auto r = pmap[y+ry][x+rx]; - if (TYP(r) && TYP(r)!=PT_VIBR && TYP(r)!=PT_BVBR && sim->elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) + if (TYP(r) && TYP(r)!=PT_VIBR && TYP(r)!=PT_BVBR && elements[TYP(r)].HeatConduct && (TYP(r)!=PT_HSWC||parts[ID(r)].life==10)) { parts[ID(r)].temp += parts[i].tmp*3; parts[i].tmp = 0; diff --git a/src/simulation/elements/VSNS.cpp b/src/simulation/elements/VSNS.cpp index baefbe56b..7c5a95de8 100644 --- a/src/simulation/elements/VSNS.cpp +++ b/src/simulation/elements/VSNS.cpp @@ -50,6 +50,8 @@ void Element::Element_VSNS() static int update(UPDATE_FUNC_ARGS) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int rd = parts[i].tmp2; if (rd > 25) parts[i].tmp2 = rd = 25; if (parts[i].life) @@ -67,7 +69,7 @@ static int update(UPDATE_FUNC_ARGS) int rt = TYP(r); if (sim->parts_avg(i, ID(r), PT_INSL) != PT_INSL) { - if ((sim->elements[rt].Properties &PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) + if ((elements[rt].Properties &PROP_CONDUCTS) && !(rt == PT_WATR || rt == PT_SLTW || rt == PT_NTCT || rt == PT_PTCT || rt == PT_INWR) && parts[ID(r)].life == 0) { parts[ID(r)].life = 4; parts[ID(r)].ctype = rt; @@ -98,7 +100,7 @@ static int update(UPDATE_FUNC_ARGS) { case 1: // serialization - if (TYP(r) != PT_VSNS && TYP(r) != PT_FILT && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)) + if (TYP(r) != PT_VSNS && TYP(r) != PT_FILT && !(elements[TYP(r)].Properties & TYPE_SOLID)) { doSerialization = true; Vs = Vm; @@ -118,12 +120,12 @@ static int update(UPDATE_FUNC_ARGS) break; case 2: // Invert mode - if (!(sim->elements[TYP(r)].Properties & TYPE_SOLID) && Vm <= parts[i].temp - 273.15) + if (!(elements[TYP(r)].Properties & TYPE_SOLID) && Vm <= parts[i].temp - 273.15) parts[i].life = 1; break; default: // Normal mode - if (!(sim->elements[TYP(r)].Properties & TYPE_SOLID) && Vm > parts[i].temp - 273.15) + if (!(elements[TYP(r)].Properties & TYPE_SOLID) && Vm > parts[i].temp - 273.15) parts[i].life = 1; break; } @@ -158,7 +160,7 @@ static int update(UPDATE_FUNC_ARGS) //Deserialization. if (doDeserialization) { - if (TYP(r) != PT_FILT && !(sim->elements[TYP(r)].Properties & TYPE_SOLID)) + if (TYP(r) != PT_FILT && !(elements[TYP(r)].Properties & TYPE_SOLID)) { float Vx = parts[ID(r)].vx; float Vy = parts[ID(r)].vy; diff --git a/src/simulation/simtools/MIX.cpp b/src/simulation/simtools/MIX.cpp index 2b79e15ee..eb2ffcf99 100644 --- a/src/simulation/simtools/MIX.cpp +++ b/src/simulation/simtools/MIX.cpp @@ -16,6 +16,8 @@ void SimTool::Tool_MIX() static int perform(Simulation * sim, Particle * cpart, int x, int y, int brushX, int brushY, float strength) { + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; int thisPart = sim->pmap[y][x]; if(!thisPart) return 0; @@ -25,7 +27,7 @@ static int perform(Simulation * sim, Particle * cpart, int x, int y, int brushX, int distance = (int)(std::pow(strength, .5f) * 10); - if(!(sim->elements[TYP(thisPart)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS))) + if(!(elements[TYP(thisPart)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS))) return 0; int newX = x + (sim->rng() % distance) - (distance/2); @@ -38,7 +40,7 @@ static int perform(Simulation * sim, Particle * cpart, int x, int y, int brushX, if(!thatPart) return 0; - if ((sim->elements[TYP(thisPart)].Properties&STATE_FLAGS) != (sim->elements[TYP(thatPart)].Properties&STATE_FLAGS)) + if ((elements[TYP(thisPart)].Properties&STATE_FLAGS) != (elements[TYP(thatPart)].Properties&STATE_FLAGS)) return 0; sim->pmap[y][x] = thatPart; From f8ee7aa0f7798dcdae12bddeb5d6cbf70dd7f0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Fri, 8 Dec 2023 22:10:35 +0100 Subject: [PATCH 02/12] Sort out constness of Simulation::PlanMove And a bunch of other member functions. This got rid of some nasty assumptions documented only in the form of comments, in exchange for some nasty template nonsense. --- src/debug/SurfaceNormals.cpp | 6 +-- src/debug/SurfaceNormals.h | 4 +- src/simulation/Simulation.cpp | 92 ++++++++++++++++++++++++----------- src/simulation/Simulation.h | 20 ++++---- 4 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/debug/SurfaceNormals.cpp b/src/debug/SurfaceNormals.cpp index 9cf8e6da1..da034f796 100644 --- a/src/debug/SurfaceNormals.cpp +++ b/src/debug/SurfaceNormals.cpp @@ -6,7 +6,7 @@ #include "simulation/ElementClasses.h" #include "graphics/Graphics.h" -SurfaceNormals::SurfaceNormals(unsigned int id, Simulation *newSim, GameView *newView, GameController *newController) : +SurfaceNormals::SurfaceNormals(unsigned int id, const Simulation *newSim, GameView *newView, GameController *newController) : DebugInfo(id), sim(newSim), view(newView), controller(newController) { } @@ -29,7 +29,7 @@ void SurfaceNormals::Draw() auto &parts = sim->parts; auto x = int(parts[i].x + 0.5f); auto y = int(parts[i].y + 0.5f); - auto mr = sim->PlanMove(i, x, y, false); + auto mr = Simulation::PlanMove(*sim, i, x, y); if (t == PT_PHOT) { if (parts[i].flags & FLAG_SKIPMOVE) @@ -48,7 +48,7 @@ void SurfaceNormals::Draw() } } } - auto gn = sim->get_normal_interp(t, parts[i].x, parts[i].y, mr.vx, mr.vy); + auto gn = sim->get_normal_interp(*sim, t, parts[i].x, parts[i].y, mr.vx, mr.vy); if (!gn.success) { return; diff --git a/src/debug/SurfaceNormals.h b/src/debug/SurfaceNormals.h index 48bcf5d96..5c767f1ea 100644 --- a/src/debug/SurfaceNormals.h +++ b/src/debug/SurfaceNormals.h @@ -6,12 +6,12 @@ class GameView; class GameController; class SurfaceNormals : public DebugInfo { - Simulation *sim; + const Simulation *sim; GameView *view; GameController *controller; public: - SurfaceNormals(unsigned int id, Simulation *newSim, GameView *newView, GameController *newController); + SurfaceNormals(unsigned int id, const Simulation *newSim, GameView *newView, GameController *newController); void Draw() override; }; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index dab7bbd2e..a2fa78680 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -18,6 +18,11 @@ extern int Element_LOLZ_lolz[XRES/9][YRES/9]; extern int Element_LOVE_RuleTable[9][9]; extern int Element_LOVE_love[XRES/9][YRES/9]; +static float remainder_p(float x, float y) +{ + return std::fmod(x, y) + (x>=0 ? 0 : y); +} + MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates { MissingElements missingElements; @@ -1620,7 +1625,7 @@ void Simulation::photoelectric_effect(int nx, int ny)//create sparks from PHOT w } } -int Simulation::is_blocking(int t, int x, int y) +int Simulation::is_blocking(int t, int x, int y) const { if (t & REFRACT) { if (x<0 || y<0 || x>=XRES || y>=YRES) @@ -1633,7 +1638,7 @@ int Simulation::is_blocking(int t, int x, int y) return !eval_move(t, x, y, NULL); } -int Simulation::is_boundary(int pt, int x, int y) +int Simulation::is_boundary(int pt, int x, int y) const { if (!is_blocking(pt,x,y)) return 0; @@ -1642,7 +1647,7 @@ int Simulation::is_boundary(int pt, int x, int y) return 1; } -int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) +int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) const { static int dx[8] = {1,1,0,-1,-1,-1,0,1}; static int dy[8] = {0,1,1,1,0,-1,-1,-1}; @@ -1681,7 +1686,7 @@ int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool return 0; } -Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float dx, float dy) +Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float dx, float dy) const { int ldm, rdm, lm, rm; int lx, ly, lv, rx, ry, rv; @@ -1726,7 +1731,24 @@ Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float d return { true, nx, ny, lx, ly, rx, ry }; } -Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, float y0, float dx, float dy) + + +template +void PhotoelectricEffectHelper(Sim &sim, int x, int y); + +template<> +void PhotoelectricEffectHelper(const Simulation &sim, int x, int y) +{ +} + +template<> +void PhotoelectricEffectHelper(Simulation &sim, int x, int y) +{ + sim.photoelectric_effect(x, y); +} + +template +Simulation::GetNormalResult Simulation::get_normal_interp(Sim &sim, int pt, float x0, float y0, float dx, float dy) { int x, y, i; @@ -1740,7 +1762,7 @@ Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, floa { return { false }; } - if (is_boundary(pt, x, y)) + if (sim.is_boundary(pt, x, y)) break; x0 += dx; y0 += dy; @@ -1749,11 +1771,14 @@ Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, floa return { false }; if (pt == PT_PHOT) - photoelectric_effect(x, y); + PhotoelectricEffectHelper(sim, x, y); - return get_normal(pt, x, y, dx, dy); + return sim.get_normal(pt, x, y, dx, dy); } +template +Simulation::GetNormalResult Simulation::get_normal_interp(const Simulation &sim, int pt, float x0, float y0, float dx, float dy); + void Simulation::kill_part(int i)//kills particle number i { if (i < 0 || i >= NPART) @@ -2122,14 +2147,31 @@ void Simulation::delete_part(int x, int y)//calls kill_part with the particle lo kill_part(ID(i)); } -Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update_emap) +template +void UpdateEmapHelper(Sim &sim, int fin_x, int fin_y); + +template<> +void UpdateEmapHelper(const Simulation &sim, int fin_x, int fin_y) { +} + +template<> +void UpdateEmapHelper(Simulation &sim, int fin_x, int fin_y) +{ + if (sim.bmap[fin_y/CELL][fin_x/CELL]==WL_DETECT && sim.emap[fin_y/CELL][fin_x/CELL]<8) + sim.set_emap(fin_x/CELL, fin_y/CELL); +} + +template +Simulation::PlanMoveResult Simulation::PlanMove(Sim &sim, int i, int x, int y) +{ + auto &parts = sim.parts; + auto &bmap = sim.bmap; + auto &emap = sim.emap; + auto &pmap = sim.pmap; + auto edgeMode = sim.edgeMode; auto &sd = SimulationData::CRef(); auto &can_move = sd.can_move; - // This function would be const if not for calling set_emap if update_emap is true, - // and users of this function *expect* it to be const if update_emap is false. So - // whenever you change something here, make sure it compiles *as const* if you - // remove the set_emap call. auto t = parts[i].type; int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; @@ -2205,7 +2247,7 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update } //block if particle can't move (0), or some special cases where it returns 1 (can_move = 3 but returns 1 meaning particle will be eaten) //also photons are still blocked (slowed down) by any particle (even ones it can move through), and absorb wall also blocks particles - int eval = eval_move(t, fin_x, fin_y, NULL); + int eval = sim.eval_move(t, fin_x, fin_y, NULL); if (!eval || (can_move[t][TYP(pmap[fin_y][fin_x])] == 3 && eval == 1) || (t == PT_PHOT && pmap[fin_y][fin_x]) || bmap[fin_y/CELL][fin_x/CELL]==WL_DESTROYALL || closedEholeStart!=(bmap[fin_y/CELL][fin_x/CELL] == WL_EHOLE && !emap[fin_y/CELL][fin_x/CELL])) { // found an obstacle @@ -2215,8 +2257,7 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update clear_y = (int)(clear_yf+0.5f); break; } - if (update_emap && bmap[fin_y/CELL][fin_x/CELL]==WL_DETECT && emap[fin_y/CELL][fin_x/CELL]<8) - set_emap(fin_x/CELL, fin_y/CELL); + UpdateEmapHelper(sim, fin_x, fin_y); } } return { @@ -2233,6 +2274,9 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update }; } +template +Simulation::PlanMoveResult Simulation::PlanMove(const Simulation &sim, int i, int x, int y); + void Simulation::UpdateParticles(int start, int end) { //the main particle loop function, goes over all particles. @@ -2876,7 +2920,7 @@ killed: int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; { - auto mr = PlanMove(i, x, y, true); + auto mr = PlanMove(*this, i, x, y); fin_x = mr.fin_x; fin_y = mr.fin_y; clear_x = mr.clear_x; @@ -2973,7 +3017,7 @@ killed: int lt_glas = (lt == PT_GLAS) || (lt == PT_BGLA); if ((rt_glas && !lt_glas) || (lt_glas && !rt_glas)) { - auto gn = get_normal_interp(REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); + auto gn = get_normal_interp(*this, REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); if (!gn.success) { kill_part(i); continue; @@ -3057,7 +3101,7 @@ killed: parts[i].ctype &= mask; } - auto gn = get_normal_interp(t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); + auto gn = get_normal_interp(*this, t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); if (gn.success) { auto nrx = gn.nx; @@ -3962,16 +4006,6 @@ Simulation::Simulation(): grav->gravity_mask(); } -int Simulation::remainder_p(int x, int y) -{ - return (x % y) + (x>=0 ? 0 : y); -} - -float Simulation::remainder_p(float x, float y) -{ - return std::fmod(x, y) + (x>=0 ? 0 : y); -} - constexpr size_t ce_log2(size_t n) { return ((n < 2) ? 1 : 1 + ce_log2(n / 2)); diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 4a71591ba..c9530f041 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -122,21 +122,24 @@ public: std::unique_ptr CreateSnapshot() const; void Restore(const Snapshot &snap); - int is_blocking(int t, int x, int y); - int is_boundary(int pt, int x, int y); - int find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse); + int is_blocking(int t, int x, int y) const; + int is_boundary(int pt, int x, int y) const; + int find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) const; void photoelectric_effect(int nx, int ny); int do_move(int i, int x, int y, float nxf, float nyf); bool move(int i, int x, int y, float nxf, float nyf); int try_move(int i, int x, int y, int nx, int ny); int eval_move(int pt, int nx, int ny, unsigned *rr) const; + struct PlanMoveResult { int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; float vx, vy; }; - PlanMoveResult PlanMove(int i, int x, int y, bool update_emap); + template + static PlanMoveResult PlanMove(Sim &sim, int i, int x, int y); + bool IsWallBlocking(int x, int y, int type) const; void create_cherenkov_photon(int pp); void create_gain_photon(int pp); @@ -207,16 +210,13 @@ public: float nx, ny; int lx, ly, rx, ry; }; - GetNormalResult get_normal(int pt, int x, int y, float dx, float dy); - GetNormalResult get_normal_interp(int pt, float x0, float y0, float dx, float dy); + GetNormalResult get_normal(int pt, int x, int y, float dx, float dy) const; + template + static GetNormalResult get_normal_interp(Sim &sim, int pt, float x0, float y0, float dx, float dy); void clear_sim(); Simulation(); ~Simulation(); - // These don't really belong anywhere at the moment, so go here for loop edge mode - static int remainder_p(int x, int y); - static float remainder_p(float x, float y); - private: CoordStack& getCoordStackSingleton(); }; From 78314a8f7d6f9a0b4a6f2508428d3b36bff75af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Fri, 8 Dec 2023 23:27:29 +0100 Subject: [PATCH 03/12] Move Simulation::platent to Element::LatentHeat Also put the feature gated by the macro REALISTIC behind the constexpr LATENTHEAT in SimulationConfig.h. --- src/SimulationConfig.h | 2 + src/gui/game/IntroText.h | 8 +- src/lua/LegacyLuaAPI.cpp | 3 + src/simulation/Element.cpp | 2 + src/simulation/Element.h | 1 + src/simulation/Simulation.cpp | 238 +++++++++++++++++------------- src/simulation/SimulationData.cpp | 169 --------------------- src/simulation/SimulationData.h | 1 - src/simulation/elements/CBNW.cpp | 1 + src/simulation/elements/DSTW.cpp | 1 + src/simulation/elements/ICEI.cpp | 1 + src/simulation/elements/METL.cpp | 1 + src/simulation/elements/SLTW.cpp | 1 + src/simulation/elements/SNOW.cpp | 1 + src/simulation/elements/WATR.cpp | 1 + 15 files changed, 152 insertions(+), 279 deletions(-) diff --git a/src/SimulationConfig.h b/src/SimulationConfig.h index 1fd9aef83..f98f29be6 100644 --- a/src/SimulationConfig.h +++ b/src/SimulationConfig.h @@ -61,3 +61,5 @@ constexpr float GLASS_IOR = 1.9f; constexpr float GLASS_DISP = 0.07f; constexpr float R_TEMP = 22; + +constexpr bool LATENTHEAT = false; diff --git a/src/gui/game/IntroText.h b/src/gui/game/IntroText.h index ba094c0f0..36f66b9dc 100644 --- a/src/gui/game/IntroText.h +++ b/src/gui/game/IntroText.h @@ -1,5 +1,6 @@ #pragma once #include "Config.h" +#include "SimulationConfig.h" #include "common/String.h" inline ByteString VersionInfo() @@ -23,9 +24,10 @@ inline ByteString VersionInfo() { sb << " LUACONSOLE"; } -#ifdef REALISTIC - sb << " REALISTIC"; -#endif + if constexpr (LATENTHEAT) + { + sb << " LATENTHEAT"; + } if constexpr (NOHTTP) { sb << " NOHTTP"; diff --git a/src/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index 93dd81006..06ade0ef2 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -26,12 +26,15 @@ void initLegacyProps() std::vector properties = Element::GetProperties(); for (auto prop : properties) { + // TODO: move aliases to the property table in Element.cpp? if (prop.Name == "MenuVisible") legacyPropNames.insert(std::pair("menu", prop)); else if (prop.Name == "PhotonReflectWavelengths") continue; else if (prop.Name == "CarriesTypeIn") continue; + else if (prop.Name == "LatentHeat") + continue; else if (prop.Name == "Temperature") legacyPropNames.insert(std::pair("heat", prop)); else if (prop.Name == "HeatConduct") diff --git a/src/simulation/Element.cpp b/src/simulation/Element.cpp index fb5d67faa..ccf217cd9 100644 --- a/src/simulation/Element.cpp +++ b/src/simulation/Element.cpp @@ -29,6 +29,7 @@ Element::Element(): Weight(50), HeatConduct(128), + LatentHeat(0), Description("No description"), Properties(TYPE_SOLID), @@ -80,6 +81,7 @@ std::vector const &Element::GetProperties() { "Weight", StructProperty::Integer, offsetof(Element, Weight ) }, { "Temperature", StructProperty::Float, offsetof(Element, DefaultProperties.temp ) }, { "HeatConduct", StructProperty::UChar, offsetof(Element, HeatConduct ) }, + { "LatentHeat", StructProperty::UInteger, offsetof(Element, LatentHeat ) }, { "Description", StructProperty::String, offsetof(Element, Description ) }, { "State", StructProperty::Removed, 0 }, { "Properties", StructProperty::Integer, offsetof(Element, Properties ) }, diff --git a/src/simulation/Element.h b/src/simulation/Element.h index 8610273bd..791984737 100644 --- a/src/simulation/Element.h +++ b/src/simulation/Element.h @@ -38,6 +38,7 @@ public: unsigned int PhotonReflectWavelengths; int Weight; unsigned char HeatConduct; + unsigned int LatentHeat; String Description; unsigned int Properties; unsigned int CarriesTypeIn; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index a2fa78680..7416bb684 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -2376,14 +2376,17 @@ void Simulation::UpdateParticles(int start, int end) if (elements[t].Diffusion)//the random diffusion that gasses have { -#ifdef REALISTIC - //The magic number controls diffusion speed - parts[i].vx += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); - parts[i].vy += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); -#else - parts[i].vx += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); - parts[i].vy += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); -#endif + if constexpr (LATENTHEAT) + { + //The magic number controls diffusion speed + parts[i].vx += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + parts[i].vy += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + } + else + { + parts[i].vx += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + parts[i].vy += elements[t].Diffusion*(2.0f*rng.uniform01()-1.0f); + } } auto transitionOccurred = false; @@ -2434,35 +2437,41 @@ void Simulation::UpdateParticles(int start, int end) } //heat transfer code -#ifdef REALISTIC - if (t&&(t!=PT_HSWC||parts[i].life==10)&&(elements[t].HeatConduct*gel_scale)) -#else auto h_count = 0; - if (t && (t!=PT_HSWC||parts[i].life==10) && rng.chance(int(elements[t].HeatConduct*gel_scale), 250)) -#endif + bool cond; + if constexpr (LATENTHEAT) + { + cond = t && (t!=PT_HSWC||parts[i].life==10) && elements[t].HeatConduct*gel_scale > 0; + } + else + { + cond = t && (t!=PT_HSWC||parts[i].life==10) && rng.chance(int(elements[t].HeatConduct*gel_scale), 250); + } + if (cond) { if (aheat_enable && !(elements[t].Properties&PROP_NOAMBHEAT)) { -#ifdef REALISTIC - auto c_heat = parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + hv[y/CELL][x/CELL]*100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; - float c_Cm = 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + 100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; - auto pt = c_heat/c_Cm; - pt = restrict_flt(pt, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); - parts[i].temp = pt; - //Pressure increase from heat (temporary) - pv[y/CELL][x/CELL] += (pt-hv[y/CELL][x/CELL])*0.004; - hv[y/CELL][x/CELL] = pt; -#else - auto c_heat = (hv[y/CELL][x/CELL]-parts[i].temp)*0.04; - c_heat = restrict_flt(c_heat, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); - parts[i].temp += c_heat; - hv[y/CELL][x/CELL] -= c_heat; -#endif + if constexpr (LATENTHEAT) + { + auto c_heat = parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight) + hv[y/CELL][x/CELL]*100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; + float c_Cm = 96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight) + 100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; + auto pt = c_heat/c_Cm; + pt = restrict_flt(pt, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); + parts[i].temp = pt; + //Pressure increase from heat (temporary) + pv[y/CELL][x/CELL] += (pt-hv[y/CELL][x/CELL])*0.004; + hv[y/CELL][x/CELL] = pt; + } + else + { + auto c_heat = (hv[y/CELL][x/CELL]-parts[i].temp)*0.04; + c_heat = restrict_flt(c_heat, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); + parts[i].temp += c_heat; + hv[y/CELL][x/CELL] -= c_heat; + } } auto c_heat = 0.0f; -#ifdef REALISTIC float c_Cm = 0.0f; -#endif int surround_hconduct[8]; for (auto j=0; j<8; j++) { @@ -2480,41 +2489,47 @@ void Simulation::UpdateParticles(int start, int end) && (t!=PT_FILT || rt!=PT_HSWC || parts[ID(r)].tmp != 1)) { surround_hconduct[j] = ID(r); -#ifdef REALISTIC - if (rt==PT_GEL) - gel_scale = parts[ID(r)].tmp*2.55f; - else gel_scale = 1.0f; + if constexpr (LATENTHEAT) + { + if (rt==PT_GEL) + gel_scale = parts[ID(r)].tmp*2.55f; + else gel_scale = 1.0f; - c_heat += parts[ID(r)].temp*96.645/elements[rt].HeatConduct*gel_scale*fabs(elements[rt].Weight); - c_Cm += 96.645/elements[rt].HeatConduct*gel_scale*fabs(elements[rt].Weight); -#else - c_heat += parts[ID(r)].temp; -#endif + c_heat += parts[ID(r)].temp*96.645/elements[rt].HeatConduct*gel_scale*std::fabs(elements[rt].Weight); + c_Cm += 96.645/elements[rt].HeatConduct*gel_scale*std::fabs(elements[rt].Weight); + } + else + { + c_heat += parts[ID(r)].temp; + } h_count++; } } float pt = R_TEMP; -#ifdef REALISTIC - if (t==PT_GEL) - gel_scale = parts[i].tmp*2.55f; - else gel_scale = 1.0f; - - if (t == PT_PHOT) - pt = (c_heat+parts[i].temp*96.645)/(c_Cm+96.645); - else - pt = (c_heat+parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight))/(c_Cm+96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight)); - - c_heat += parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight); - c_Cm += 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight); - parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); -#else - pt = (c_heat+parts[i].temp)/(h_count+1); - pt = parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); - for (auto j=0; j<8; j++) + if constexpr (LATENTHEAT) { - parts[surround_hconduct[j]].temp = pt; + if (t==PT_GEL) + gel_scale = parts[i].tmp*2.55f; + else gel_scale = 1.0f; + + if (t == PT_PHOT) + pt = (c_heat+parts[i].temp*96.645)/(c_Cm+96.645); + else + pt = (c_heat+parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight))/(c_Cm+96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight)); + + c_heat += parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight); + c_Cm += 96.645/elements[t].HeatConduct*gel_scale*std::fabs(elements[t].Weight); + parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); + } + else + { + pt = (c_heat+parts[i].temp)/(h_count+1); + pt = parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); + for (auto j=0; j<8; j++) + { + parts[surround_hconduct[j]].temp = pt; + } } -#endif auto ctemph = pt; auto ctempl = pt; @@ -2534,25 +2549,27 @@ void Simulation::UpdateParticles(int start, int end) if (elements[t].HighTemperatureTransition>-1 && ctemph>=elements[t].HighTemperature) { // particle type change due to high temperature -#ifdef REALISTIC float dbt = ctempl - pt; if (elements[t].HighTemperatureTransition != PT_NUM) { - if (platent[t] <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) { - pt = (c_heat - platent[t])/c_Cm; - t = elements[t].HighTemperatureTransition; + if (elements[t].LatentHeat <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + { + pt = (c_heat - elements[t].LatentHeat)/c_Cm; + t = elements[t].HighTemperatureTransition; + } + else + { + parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } } else { - parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; + t = elements[t].HighTemperatureTransition; } } -#else - if (elements[t].HighTemperatureTransition != PT_NUM) - t = elements[t].HighTemperatureTransition; -#endif else if (t == PT_ICEI || t == PT_SNOW) { if (parts[i].ctype > 0 && parts[i].ctype < PT_NUM && parts[i].ctype != t) @@ -2567,25 +2584,28 @@ void Simulation::UpdateParticles(int start, int end) if (s) { -#ifdef REALISTIC - //One ice table value for all it's kinds - if (platent[t] <= (c_heat - (elements[parts[i].ctype].LowTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) + { + //One ice table value for all it's kinds + if (elements[t].LatentHeat <= (c_heat - (elements[parts[i].ctype].LowTemperature - dbt)*c_Cm)) + { + pt = (c_heat - elements[t].LatentHeat)/c_Cm; + t = parts[i].ctype; + parts[i].ctype = PT_NONE; + parts[i].life = 0; + } + else + { + parts[i].temp = restrict_flt(elements[parts[i].ctype].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } + } + else { - pt = (c_heat - platent[t])/c_Cm; t = parts[i].ctype; parts[i].ctype = PT_NONE; parts[i].life = 0; } - else - { - parts[i].temp = restrict_flt(elements[parts[i].ctype].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; - } -#else - t = parts[i].ctype; - parts[i].ctype = PT_NONE; - parts[i].life = 0; -#endif } } else @@ -2593,21 +2613,24 @@ void Simulation::UpdateParticles(int start, int end) } else if (t == PT_SLTW) { -#ifdef REALISTIC - if (platent[t] <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) { - pt = (c_heat - platent[t])/c_Cm; + if (elements[t].LatentHeat <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm)) + { + pt = (c_heat - elements[t].LatentHeat)/c_Cm; - t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; + t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; + } + else + { + parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } } else { - parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; + t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; } -#else - t = rng.chance(1, 4) ? PT_SALT : PT_WTRV; -#endif } else if (t == PT_BRMT) { @@ -2640,25 +2663,27 @@ void Simulation::UpdateParticles(int start, int end) else if (elements[t].LowTemperatureTransition > -1 && ctempl= (c_heat - (elements[t].LowTemperature - dbt)*c_Cm)) + if constexpr (LATENTHEAT) { - pt = (c_heat + platent[elements[t].LowTemperatureTransition])/c_Cm; - t = elements[t].LowTemperatureTransition; + if (elements[elements[t].LowTemperatureTransition].LatentHeat >= (c_heat - (elements[t].LowTemperature - dbt)*c_Cm)) + { + pt = (c_heat + elements[elements[t].LowTemperatureTransition].LatentHeat)/c_Cm; + t = elements[t].LowTemperatureTransition; + } + else + { + parts[i].temp = restrict_flt(elements[t].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); + s = 0; + } } else { - parts[i].temp = restrict_flt(elements[t].LowTemperature - dbt, MIN_TEMP, MAX_TEMP); - s = 0; + t = elements[t].LowTemperatureTransition; } } -#else - if (elements[t].LowTemperatureTransition != PT_NUM) - t = elements[t].LowTemperatureTransition; -#endif else if (t == PT_WTRV) { t = (pt < 273.0f) ? PT_RIME : PT_DSTW; @@ -2717,13 +2742,14 @@ void Simulation::UpdateParticles(int start, int end) } else s = 0; -#ifdef REALISTIC - pt = restrict_flt(pt, MIN_TEMP, MAX_TEMP); - for (auto j=0; j<8; j++) + if constexpr (LATENTHEAT) { - parts[surround_hconduct[j]].temp = pt; + pt = restrict_flt(pt, MIN_TEMP, MAX_TEMP); + for (auto j=0; j<8; j++) + { + parts[surround_hconduct[j]].temp = pt; + } } -#endif if (s) // particle type change occurred { if (t==PT_ICEI || t==PT_LAVA || t==PT_SNOW) diff --git a/src/simulation/SimulationData.cpp b/src/simulation/SimulationData.cpp index a6a9ba39c..1e101a851 100644 --- a/src/simulation/SimulationData.cpp +++ b/src/simulation/SimulationData.cpp @@ -98,174 +98,6 @@ static std::vector LoadMenus() }; } -static std::vector LoadLatent() -{ - return - std::vector{ - /* NONE */ 0, - /* DUST */ 0, - /* WATR */ 7500, - /* OIL */ 0, - /* FIRE */ 0, - /* STNE */ 0, - /* LAVA */ 0, - /* GUN */ 0, - /* NITR */ 0, - /* CLNE */ 0, - /* GAS */ 0, - /* C-4 */ 0, - /* GOO */ 0, - /* ICE */ 1095, - /* METL */ 919, - /* SPRK */ 0, - /* SNOW */ 1095, - /* WOOD */ 0, - /* NEUT */ 0, - /* PLUT */ 0, - /* PLNT */ 0, - /* ACID */ 0, - /* VOID */ 0, - /* WTRV */ 0, - /* CNCT */ 0, - /* DSTW */ 7500, - /* SALT */ 0, - /* SLTW */ 7500, - /* DMND */ 0, - /* BMTL */ 0, - /* BRMT */ 0, - /* PHOT */ 0, - /* URAN */ 0, - /* WAX */ 0, - /* MWAX */ 0, - /* PSCN */ 0, - /* NSCN */ 0, - /* LN2 */ 0, - /* INSL */ 0, - /* VACU */ 0, - /* VENT */ 0, - /* RBDM */ 0, - /* LRBD */ 0, - /* NTCT */ 0, - /* SAND */ 0, - /* GLAS */ 0, - /* PTCT */ 0, - /* BGLA */ 0, - /* THDR */ 0, - /* PLSM */ 0, - /* ETRD */ 0, - /* NICE */ 0, - /* NBLE */ 0, - /* BTRY */ 0, - /* LCRY */ 0, - /* STKM */ 0, - /* SWCH */ 0, - /* SMKE */ 0, - /* DESL */ 0, - /* COAL */ 0, - /* LO2 */ 0, - /* O2 */ 0, - /* INWR */ 0, - /* YEST */ 0, - /* DYST */ 0, - /* THRM */ 0, - /* GLOW */ 0, - /* BRCK */ 0, - /* CFLM */ 0, - /* FIRW */ 0, - /* FUSE */ 0, - /* FSEP */ 0, - /* AMTR */ 0, - /* BCOL */ 0, - /* PCLN */ 0, - /* HSWC */ 0, - /* IRON */ 0, - /* MORT */ 0, - /* LIFE */ 0, - /* DLAY */ 0, - /* CO2 */ 0, - /* DRIC */ 0, - /* CBNW */ 7500, - /* STOR */ 0, - /* STOR */ 0, - /* FREE */ 0, - /* FREE */ 0, - /* FREE */ 0, - /* FREE */ 0, - /* FREE */ 0, - /* SPNG */ 0, - /* RIME */ 0, - /* FOG */ 0, - /* BCLN */ 0, - /* LOVE */ 0, - /* DEUT */ 0, - /* WARP */ 0, - /* PUMP */ 0, - /* FWRK */ 0, - /* PIPE */ 0, - /* FRZZ */ 0, - /* FRZW */ 0, - /* GRAV */ 0, - /* BIZR */ 0, - /* BIZRG*/ 0, - /* BIZRS*/ 0, - /* INST */ 0, - /* ISOZ */ 0, - /* ISZS */ 0, - /* PRTI */ 0, - /* PRTO */ 0, - /* PSTE */ 0, - /* PSTS */ 0, - /* ANAR */ 0, - /* VINE */ 0, - /* INVS */ 0, - /* EQVE */ 0, - /* SPWN2*/ 0, - /* SPAWN*/ 0, - /* SHLD1*/ 0, - /* SHLD2*/ 0, - /* SHLD3*/ 0, - /* SHLD4*/ 0, - /* LOlZ */ 0, - /* WIFI */ 0, - /* FILT */ 0, - /* ARAY */ 0, - /* BRAY */ 0, - /* STKM2*/ 0, - /* BOMB */ 0, - /* C-5 */ 0, - /* SING */ 0, - /* QRTZ */ 0, - /* PQRT */ 0, - /* EMP */ 0, - /* BREL */ 0, - /* ELEC */ 0, - /* ACEL */ 0, - /* DCEL */ 0, - /* TNT */ 0, - /* IGNP */ 0, - /* BOYL */ 0, - /* GEL */ 0, - /* FREE */ 0, - /* FREE */ 0, - /* FREE */ 0, - /* FREE */ 0, - /* WIND */ 0, - /* H2 */ 0, - /* SOAP */ 0, - /* NBHL */ 0, - /* NWHL */ 0, - /* MERC */ 0, - /* PBCN */ 0, - /* GPMP */ 0, - /* CLST */ 0, - /* WIRE */ 0, - /* GBMB */ 0, - /* FIGH */ 0, - /* FRAY */ 0, - /* REPL */ 0, - }; -} - void SimulationData::init_can_move() { int movingType, destinationType; @@ -504,7 +336,6 @@ SimulationData::SimulationData() init_can_move(); msections = LoadMenus(); wtypes = LoadWalls(); - platent = LoadLatent(); elements = GetElements(); tools = GetTools(); } diff --git a/src/simulation/SimulationData.h b/src/simulation/SimulationData.h index 9f92f7725..6f7ae5421 100644 --- a/src/simulation/SimulationData.h +++ b/src/simulation/SimulationData.h @@ -174,7 +174,6 @@ class SimulationData : public ExplicitSingleton public: std::array elements; std::vector tools; - std::vector platent; std::vector wtypes; std::vector msections; char can_move[PT_NUM][PT_NUM]; diff --git a/src/simulation/elements/CBNW.cpp b/src/simulation/elements/CBNW.cpp index ac3b09d1e..0c81ce7d2 100644 --- a/src/simulation/elements/CBNW.cpp +++ b/src/simulation/elements/CBNW.cpp @@ -31,6 +31,7 @@ void Element::Element_CBNW() DefaultProperties.temp = R_TEMP - 2.0f + 273.15f; HeatConduct = 29; + LatentHeat = 7500; Description = "Carbonated water. Slowly releases CO2."; Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE; diff --git a/src/simulation/elements/DSTW.cpp b/src/simulation/elements/DSTW.cpp index 5565bf53b..6d097c327 100644 --- a/src/simulation/elements/DSTW.cpp +++ b/src/simulation/elements/DSTW.cpp @@ -30,6 +30,7 @@ void Element::Element_DSTW() DefaultProperties.temp = R_TEMP - 2.0f + 273.15f; HeatConduct = 23; + LatentHeat = 7500; Description = "Distilled water, does not conduct electricity."; Properties = TYPE_LIQUID|PROP_NEUTPASS; diff --git a/src/simulation/elements/ICEI.cpp b/src/simulation/elements/ICEI.cpp index db533fb9f..a69572184 100644 --- a/src/simulation/elements/ICEI.cpp +++ b/src/simulation/elements/ICEI.cpp @@ -30,6 +30,7 @@ void Element::Element_ICEI() DefaultProperties.temp = R_TEMP - 50.0f + 273.15f; HeatConduct = 46; + LatentHeat = 1095; Description = "Crushes under pressure. Cools down air."; Properties = TYPE_SOLID|PROP_LIFE_DEC|PROP_NEUTPASS; diff --git a/src/simulation/elements/METL.cpp b/src/simulation/elements/METL.cpp index bcb3656ef..122fe30cf 100644 --- a/src/simulation/elements/METL.cpp +++ b/src/simulation/elements/METL.cpp @@ -27,6 +27,7 @@ void Element::Element_METL() Weight = 100; HeatConduct = 251; + LatentHeat = 919; Description = "The basic conductor. Meltable."; Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW; diff --git a/src/simulation/elements/SLTW.cpp b/src/simulation/elements/SLTW.cpp index 2a3805f23..95423b398 100644 --- a/src/simulation/elements/SLTW.cpp +++ b/src/simulation/elements/SLTW.cpp @@ -29,6 +29,7 @@ void Element::Element_SLTW() Weight = 35; HeatConduct = 75; + LatentHeat = 7500; Description = "Saltwater, conducts electricity, difficult to freeze."; Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE; diff --git a/src/simulation/elements/SNOW.cpp b/src/simulation/elements/SNOW.cpp index e729db65c..08b273cb0 100644 --- a/src/simulation/elements/SNOW.cpp +++ b/src/simulation/elements/SNOW.cpp @@ -31,6 +31,7 @@ void Element::Element_SNOW() DefaultProperties.temp = R_TEMP - 30.0f + 273.15f; HeatConduct = 46; + LatentHeat = 1095; Description = "Light particles. Created when ICE breaks under pressure."; Properties = TYPE_PART|PROP_NEUTPASS; diff --git a/src/simulation/elements/WATR.cpp b/src/simulation/elements/WATR.cpp index 2e82c5e06..849682903 100644 --- a/src/simulation/elements/WATR.cpp +++ b/src/simulation/elements/WATR.cpp @@ -30,6 +30,7 @@ void Element::Element_WATR() DefaultProperties.temp = R_TEMP - 2.0f + 273.15f; HeatConduct = 29; + LatentHeat = 7500; Description = "Water. Conducts electricity, freezes, and extinguishes fires."; Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPASS; From e64c23d50d7f313dae29c0d1fd97878737580140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 00:38:12 +0100 Subject: [PATCH 04/12] Limit access to the LatentHeat property to LATENTHEAT builds --- src/simulation/Element.cpp | 90 +++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/src/simulation/Element.cpp b/src/simulation/Element.cpp index ccf217cd9..ec46e4353 100644 --- a/src/simulation/Element.cpp +++ b/src/simulation/Element.cpp @@ -55,46 +55,58 @@ Element::Element(): std::vector const &Element::GetProperties() { - static std::vector properties = { - { "Name", StructProperty::String, offsetof(Element, Name ) }, - { "Colour", StructProperty::Colour, offsetof(Element, Colour ) }, - { "Color", StructProperty::Colour, offsetof(Element, Colour ) }, - { "MenuVisible", StructProperty::Integer, offsetof(Element, MenuVisible ) }, - { "MenuSection", StructProperty::Integer, offsetof(Element, MenuSection ) }, - { "Enabled", StructProperty::Integer, offsetof(Element, Enabled ) }, - { "Advection", StructProperty::Float, offsetof(Element, Advection ) }, - { "AirDrag", StructProperty::Float, offsetof(Element, AirDrag ) }, - { "AirLoss", StructProperty::Float, offsetof(Element, AirLoss ) }, - { "Loss", StructProperty::Float, offsetof(Element, Loss ) }, - { "Collision", StructProperty::Float, offsetof(Element, Collision ) }, - { "Gravity", StructProperty::Float, offsetof(Element, Gravity ) }, - { "NewtonianGravity", StructProperty::Float, offsetof(Element, NewtonianGravity ) }, - { "Diffusion", StructProperty::Float, offsetof(Element, Diffusion ) }, - { "HotAir", StructProperty::Float, offsetof(Element, HotAir ) }, - { "Falldown", StructProperty::Integer, offsetof(Element, Falldown ) }, - { "Flammable", StructProperty::Integer, offsetof(Element, Flammable ) }, - { "Explosive", StructProperty::Integer, offsetof(Element, Explosive ) }, - { "Meltable", StructProperty::Integer, offsetof(Element, Meltable ) }, - { "Hardness", StructProperty::Integer, offsetof(Element, Hardness ) }, - { "PhotonReflectWavelengths", StructProperty::UInteger, offsetof(Element, PhotonReflectWavelengths ) }, - { "CarriesTypeIn", StructProperty::UInteger, offsetof(Element, CarriesTypeIn ) }, - { "Weight", StructProperty::Integer, offsetof(Element, Weight ) }, - { "Temperature", StructProperty::Float, offsetof(Element, DefaultProperties.temp ) }, - { "HeatConduct", StructProperty::UChar, offsetof(Element, HeatConduct ) }, - { "LatentHeat", StructProperty::UInteger, offsetof(Element, LatentHeat ) }, - { "Description", StructProperty::String, offsetof(Element, Description ) }, - { "State", StructProperty::Removed, 0 }, - { "Properties", StructProperty::Integer, offsetof(Element, Properties ) }, - { "LowPressure", StructProperty::Float, offsetof(Element, LowPressure ) }, - { "LowPressureTransition", StructProperty::TransitionType, offsetof(Element, LowPressureTransition ) }, - { "HighPressure", StructProperty::Float, offsetof(Element, HighPressure ) }, - { "HighPressureTransition", StructProperty::TransitionType, offsetof(Element, HighPressureTransition ) }, - { "LowTemperature", StructProperty::Float, offsetof(Element, LowTemperature ) }, - { "LowTemperatureTransition", StructProperty::TransitionType, offsetof(Element, LowTemperatureTransition ) }, - { "HighTemperature", StructProperty::Float, offsetof(Element, HighTemperature ) }, - { "HighTemperatureTransition", StructProperty::TransitionType, offsetof(Element, HighTemperatureTransition) } + struct DoOnce + { + std::vector properties; + + DoOnce() + { + properties = { + { "Name", StructProperty::String, offsetof(Element, Name ) }, + { "Colour", StructProperty::Colour, offsetof(Element, Colour ) }, + { "Color", StructProperty::Colour, offsetof(Element, Colour ) }, + { "MenuVisible", StructProperty::Integer, offsetof(Element, MenuVisible ) }, + { "MenuSection", StructProperty::Integer, offsetof(Element, MenuSection ) }, + { "Enabled", StructProperty::Integer, offsetof(Element, Enabled ) }, + { "Advection", StructProperty::Float, offsetof(Element, Advection ) }, + { "AirDrag", StructProperty::Float, offsetof(Element, AirDrag ) }, + { "AirLoss", StructProperty::Float, offsetof(Element, AirLoss ) }, + { "Loss", StructProperty::Float, offsetof(Element, Loss ) }, + { "Collision", StructProperty::Float, offsetof(Element, Collision ) }, + { "Gravity", StructProperty::Float, offsetof(Element, Gravity ) }, + { "NewtonianGravity", StructProperty::Float, offsetof(Element, NewtonianGravity ) }, + { "Diffusion", StructProperty::Float, offsetof(Element, Diffusion ) }, + { "HotAir", StructProperty::Float, offsetof(Element, HotAir ) }, + { "Falldown", StructProperty::Integer, offsetof(Element, Falldown ) }, + { "Flammable", StructProperty::Integer, offsetof(Element, Flammable ) }, + { "Explosive", StructProperty::Integer, offsetof(Element, Explosive ) }, + { "Meltable", StructProperty::Integer, offsetof(Element, Meltable ) }, + { "Hardness", StructProperty::Integer, offsetof(Element, Hardness ) }, + { "PhotonReflectWavelengths", StructProperty::UInteger, offsetof(Element, PhotonReflectWavelengths ) }, + { "CarriesTypeIn", StructProperty::UInteger, offsetof(Element, CarriesTypeIn ) }, + { "Weight", StructProperty::Integer, offsetof(Element, Weight ) }, + { "Temperature", StructProperty::Float, offsetof(Element, DefaultProperties.temp ) }, + { "HeatConduct", StructProperty::UChar, offsetof(Element, HeatConduct ) }, + { "Description", StructProperty::String, offsetof(Element, Description ) }, + { "State", StructProperty::Removed, 0 }, + { "Properties", StructProperty::Integer, offsetof(Element, Properties ) }, + { "LowPressure", StructProperty::Float, offsetof(Element, LowPressure ) }, + { "LowPressureTransition", StructProperty::TransitionType, offsetof(Element, LowPressureTransition ) }, + { "HighPressure", StructProperty::Float, offsetof(Element, HighPressure ) }, + { "HighPressureTransition", StructProperty::TransitionType, offsetof(Element, HighPressureTransition ) }, + { "LowTemperature", StructProperty::Float, offsetof(Element, LowTemperature ) }, + { "LowTemperatureTransition", StructProperty::TransitionType, offsetof(Element, LowTemperatureTransition ) }, + { "HighTemperature", StructProperty::Float, offsetof(Element, HighTemperature ) }, + { "HighTemperatureTransition", StructProperty::TransitionType, offsetof(Element, HighTemperatureTransition) } + }; + if constexpr (LATENTHEAT) + { + properties.push_back({ "LatentHeat", StructProperty::UInteger, offsetof(Element, LatentHeat) }); + } + } }; - return properties; + static DoOnce doOnce; + return doOnce.properties; } int Element::legacyUpdate(UPDATE_FUNC_ARGS) { From cfa9fe568d0684eb8f3b22fbf2641302c6a5aa27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 09:51:41 +0100 Subject: [PATCH 05/12] Move graphics cache to SimulationData --- src/graphics/Renderer.cpp | 26 +++++++++++++++----------- src/graphics/Renderer.h | 25 +------------------------ src/graphics/RendererBasic.cpp | 9 --------- src/graphics/gcache_item.h | 15 +++++++++++++++ src/gui/game/GameView.cpp | 3 +++ src/gui/render/RenderView.cpp | 4 ++++ src/lua/LegacyLuaAPI.cpp | 2 +- src/lua/LuaScriptInterface.cpp | 19 +++++++------------ src/simulation/SaveRenderer.cpp | 6 ------ src/simulation/SaveRenderer.h | 1 - src/simulation/SimulationData.h | 2 ++ src/simulation/elements/PIPE.cpp | 21 +++++++++++---------- 12 files changed, 59 insertions(+), 74 deletions(-) create mode 100644 src/graphics/gcache_item.h diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 9179d52cc..569d8df26 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -173,6 +173,7 @@ void Renderer::render_parts() { auto &sd = SimulationData::CRef(); auto &elements = sd.elements; + auto &graphicscache = sd.graphicscache; int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y; int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0}; Particle * parts; @@ -244,18 +245,21 @@ void Renderer::render_parts() else if(!(colour_mode & COLOUR_BASC)) { auto *graphics = useGraphicsFunction ? elements[t].Graphics : nullptr; - if (!graphics || graphics(this, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb)) //That's a lot of args, a struct might be better + auto makeReady = !graphics || graphics(this, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb); //That's a lot of args, a struct might be better + if (makeReady && useGraphicsFunction) { - graphicscache[t].isready = 1; - graphicscache[t].pixel_mode = pixel_mode; - graphicscache[t].cola = cola; - graphicscache[t].colr = colr; - graphicscache[t].colg = colg; - graphicscache[t].colb = colb; - graphicscache[t].firea = firea; - graphicscache[t].firer = firer; - graphicscache[t].fireg = fireg; - graphicscache[t].fireb = fireb; + // I sure hope we locked sd.elementGraphicsMx exclusively + auto &wgraphicscache = SimulationData::Ref().graphicscache; + wgraphicscache[t].isready = 1; + wgraphicscache[t].pixel_mode = pixel_mode; + wgraphicscache[t].cola = cola; + wgraphicscache[t].colr = colr; + wgraphicscache[t].colg = colg; + wgraphicscache[t].colb = colb; + wgraphicscache[t].firea = firea; + wgraphicscache[t].firer = firer; + wgraphicscache[t].fireg = fireg; + wgraphicscache[t].fireb = fireb; } } if((elements[t].Properties & PROP_HOT_GLOW) && sim->parts[i].temp>(elements[t].HighTemperature-800.0f)) diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index d1f2b0909..98efee53a 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -1,5 +1,6 @@ #pragma once #include "Graphics.h" +#include "gui/game/RenderPreset.h" #include "gui/interface/Point.h" #include "common/tpt-rand.h" #include "SimulationConfig.h" @@ -13,28 +14,6 @@ class RenderPreset; class Simulation; -struct gcache_item -{ - int isready; - int pixel_mode; - int cola, colr, colg, colb; - int firea, firer, fireg, fireb; - gcache_item() : - isready(0), - pixel_mode(0), - cola(0), - colr(0), - colg(0), - colb(0), - firea(0), - firer(0), - fireg(0), - fireb(0) - { - } -}; -typedef struct gcache_item gcache_item; - int HeatToColour(float temp); class Renderer: public RasterDrawMethods @@ -65,7 +44,6 @@ public: RNG rng; Simulation * sim; - gcache_item *graphicscache; std::vector render_modes; unsigned int render_mode; @@ -148,7 +126,6 @@ public: static std::unique_ptr WallIcon(int wallID, Vec2 size); Renderer(Simulation * sim); - ~Renderer(); #define RENDERER_TABLE(name) \ static std::vector> name; \ diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index 1d4efbf08..43f892732 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -323,10 +323,6 @@ Renderer::Renderer(Simulation * sim): COLOUR_LIFE }); - //Prepare the graphics cache - graphicscache = new gcache_item[PT_NUM]; - std::fill(&graphicscache[0], &graphicscache[0] + PT_NUM, gcache_item()); - prepare_alpha(CELL, 1.0f); } @@ -466,9 +462,4 @@ VideoBuffer Renderer::DumpFrame() return newBuffer; } -Renderer::~Renderer() -{ - delete[] graphicscache; -} - template struct RasterDrawMethods; diff --git a/src/graphics/gcache_item.h b/src/graphics/gcache_item.h new file mode 100644 index 000000000..b824ae359 --- /dev/null +++ b/src/graphics/gcache_item.h @@ -0,0 +1,15 @@ +#pragma once + +struct gcache_item +{ + int isready = 0; + int pixel_mode = 0; + int cola = 0; + int colr = 0; + int colg = 0; + int colb = 0; + int firea = 0; + int firer = 0; + int fireg = 0; + int fireb = 0; +}; diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 19d9c2781..9599efc92 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -2108,6 +2108,9 @@ void GameView::OnDraw() Graphics * g = GetGraphics(); if (ren) { + // we're the main thread, we may write graphicscache + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); ren->clearScreen(); ren->RenderBegin(); ren->SetSample(c->PointTranslate(currentMouse)); diff --git a/src/gui/render/RenderView.cpp b/src/gui/render/RenderView.cpp index d64286407..2fbb19e3f 100644 --- a/src/gui/render/RenderView.cpp +++ b/src/gui/render/RenderView.cpp @@ -1,6 +1,7 @@ #include "RenderView.h" #include "simulation/ElementGraphics.h" +#include "simulation/SimulationData.h" #include "graphics/Graphics.h" #include "graphics/Renderer.h" @@ -158,6 +159,9 @@ void RenderView::OnDraw() g->DrawFilledRect(WINDOW.OriginRect(), 0x000000_rgb); if(ren) { + // we're the main thread, we may write graphicscache + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); ren->clearScreen(); ren->RenderBegin(); ren->RenderEnd(); diff --git a/src/lua/LegacyLuaAPI.cpp b/src/lua/LegacyLuaAPI.cpp index 06ade0ef2..6eae5d11a 100644 --- a/src/lua/LegacyLuaAPI.cpp +++ b/src/lua/LegacyLuaAPI.cpp @@ -263,7 +263,7 @@ int luacon_elementwrite(lua_State* l) luacon_model->BuildMenus(); auto *luacon_ci = static_cast(commandInterface); luacon_ci->custom_init_can_move(); - std::fill(&luacon_ren->graphicscache[0], &luacon_ren->graphicscache[0] + PT_NUM, gcache_item()); + sd.graphicscache = std::array(); return 0; } diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index d5625b6b7..b3e24c9bf 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -3286,6 +3286,7 @@ void LuaScriptInterface::LuaSetParticleProperty(lua_State* l, int particleID, St int LuaScriptInterface::elements_loadDefault(lua_State * l) { + auto &sd = SimulationData::Ref(); auto &builtinElements = GetElements(); auto *luacon_ci = static_cast(commandInterface); { @@ -3304,7 +3305,6 @@ int LuaScriptInterface::elements_loadDefault(lua_State * l) lua_settable(l, -3); { - auto &sd = SimulationData::Ref(); std::unique_lock lk(sd.elementGraphicsMx); auto &elements = sd.elements; if (id < (int)builtinElements.size()) @@ -3321,7 +3321,6 @@ int LuaScriptInterface::elements_loadDefault(lua_State * l) else { { - auto &sd = SimulationData::Ref(); std::unique_lock lk(sd.elementGraphicsMx); auto &elements = sd.elements; for (int i = 0; i < PT_NUM; i++) @@ -3355,8 +3354,7 @@ int LuaScriptInterface::elements_loadDefault(lua_State * l) } } luacon_ci->custom_init_can_move(); - std::fill(luacon_ren->graphicscache, luacon_ren->graphicscache+PT_NUM, gcache_item()); - SaveRenderer::Ref().Flush(0, PT_NUM); + sd.graphicscache = std::array(); return 0; } @@ -3639,8 +3637,8 @@ int LuaScriptInterface::elements_element(lua_State * l) if (lua_gettop(l) > 1) { + auto &sd = SimulationData::Ref(); { - auto &sd = SimulationData::Ref(); std::unique_lock lk(sd.elementGraphicsMx); auto &elements = sd.elements; luaL_checktype(l, 2, LUA_TTABLE); @@ -3744,8 +3742,7 @@ int LuaScriptInterface::elements_element(lua_State * l) luacon_model->BuildMenus(); luacon_ci->custom_init_can_move(); - luacon_ren->graphicscache[id].isready = 0; - SaveRenderer::Ref().Flush(id, id + 1); + sd.graphicscache[id].isready = 0; return 0; } @@ -3846,6 +3843,7 @@ int LuaScriptInterface::elements_property(lua_State * l) { if (prop != properties.end()) { + auto &sd = SimulationData::Ref(); if (lua_type(l, 3) != LUA_TNIL) { if (prop->Type == StructProperty::TransitionType) @@ -3857,7 +3855,6 @@ int LuaScriptInterface::elements_property(lua_State * l) } } { - auto &sd = SimulationData::Ref(); std::unique_lock lk(sd.elementGraphicsMx); auto &elements = sd.elements; intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset); @@ -3867,8 +3864,7 @@ int LuaScriptInterface::elements_property(lua_State * l) luacon_model->BuildMenus(); luacon_ci->custom_init_can_move(); - luacon_ren->graphicscache[id].isready = 0; - SaveRenderer::Ref().Flush(id, id + 1); + sd.graphicscache[id].isready = 0; } else if (propertyName == "Update") { @@ -3914,8 +3910,7 @@ int LuaScriptInterface::elements_property(lua_State * l) lua_gr_func[id].Clear(); elements[id].Graphics = builtinElements[id].Graphics; } - luacon_ren->graphicscache[id].isready = 0; - SaveRenderer::Ref().Flush(id, id + 1); + sd.graphicscache[id].isready = 0; } else if (propertyName == "Create") { diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index 63dea381d..65c6f73ee 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -15,12 +15,6 @@ SaveRenderer::SaveRenderer(){ ren->blackDecorations = true; } -void SaveRenderer::Flush(int begin, int end) -{ - std::lock_guard gx(renderMutex); - std::fill(ren->graphicscache + begin, ren->graphicscache + end, gcache_item()); -} - std::pair, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) { // this function usually runs on a thread different from where element info in SimulationData may be written, so we acquire a read-only lock on it diff --git a/src/simulation/SaveRenderer.h b/src/simulation/SaveRenderer.h index d2a245339..65a8ac4ab 100644 --- a/src/simulation/SaveRenderer.h +++ b/src/simulation/SaveRenderer.h @@ -20,6 +20,5 @@ class SaveRenderer: public ExplicitSingleton { public: SaveRenderer(); std::pair, MissingElements> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); - void Flush(int begin, int end); virtual ~SaveRenderer(); }; diff --git a/src/simulation/SimulationData.h b/src/simulation/SimulationData.h index 6f7ae5421..0f8bebda3 100644 --- a/src/simulation/SimulationData.h +++ b/src/simulation/SimulationData.h @@ -9,6 +9,7 @@ #include "Element.h" #include "Particle.h" #include "WallType.h" +#include "graphics/gcache_item.h" #include #include #include @@ -173,6 +174,7 @@ class SimulationData : public ExplicitSingleton { public: std::array elements; + std::array graphicscache; std::vector tools; std::vector wtypes; std::vector msections; diff --git a/src/simulation/elements/PIPE.cpp b/src/simulation/elements/PIPE.cpp index 717d7b459..51df18f27 100644 --- a/src/simulation/elements/PIPE.cpp +++ b/src/simulation/elements/PIPE.cpp @@ -348,22 +348,23 @@ int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) { auto &sd = SimulationData::CRef(); auto &elements = sd.elements; + auto &graphicscache = sd.graphicscache; int t = TYP(cpart->ctype); if (t>0 && tgraphicscache[t].isready) + if (graphicscache[t].isready) { - *pixel_mode = ren->graphicscache[t].pixel_mode; - *cola = ren->graphicscache[t].cola; - *colr = ren->graphicscache[t].colr; - *colg = ren->graphicscache[t].colg; - *colb = ren->graphicscache[t].colb; - *firea = ren->graphicscache[t].firea; - *firer = ren->graphicscache[t].firer; - *fireg = ren->graphicscache[t].fireg; - *fireb = ren->graphicscache[t].fireb; + *pixel_mode = graphicscache[t].pixel_mode; + *cola = graphicscache[t].cola; + *colr = graphicscache[t].colr; + *colg = graphicscache[t].colg; + *colb = graphicscache[t].colb; + *firea = graphicscache[t].firea; + *firer = graphicscache[t].firer; + *fireg = graphicscache[t].fireg; + *fireb = graphicscache[t].fireb; } else { From 0f1218df0ca3c3dda049823d4c2bc3f169d6403a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 11:26:07 +0100 Subject: [PATCH 06/12] Sort out constness of Simulation and Renderer in graphics functions Mostly. They are now const but only in graphics functions called from secondary Renderers. The primary (main thread) Renderer still allows graphics functions to mutate Simulation; this is required for correct in-PIPE rendering of custom elements. --- src/graphics/Renderer.cpp | 30 ++++++++++------- src/graphics/Renderer.h | 17 +++++++--- src/graphics/RendererBasic.cpp | 6 ++-- src/gui/game/GOLTool.cpp | 8 ++--- src/gui/game/GameModel.cpp | 2 +- src/lua/LuaScriptInterface.cpp | 16 ++++++++- src/simulation/Element.h | 1 + src/simulation/ElementDefs.h | 4 +-- src/simulation/SaveRenderer.cpp | 15 ++++----- src/simulation/SaveRenderer.h | 11 +++--- src/simulation/Sign.cpp | 2 +- src/simulation/Sign.h | 2 +- src/simulation/Simulation.cpp | 32 ------------------ src/simulation/Simulation.h | 4 +-- src/simulation/elements/CRAY.cpp | 1 - src/simulation/elements/EMBR.cpp | 4 +-- src/simulation/elements/EXOT.cpp | 2 +- src/simulation/elements/FILT.cpp | 3 +- src/simulation/elements/GLOW.cpp | 2 +- src/simulation/elements/GOLD.cpp | 2 +- src/simulation/elements/GRAV.cpp | 12 +++---- src/simulation/elements/LCRY.cpp | 4 +-- src/simulation/elements/LDTC.cpp | 1 - src/simulation/elements/LIFE.cpp | 4 +-- src/simulation/elements/LITH.cpp | 2 +- src/simulation/elements/PIPE.cpp | 58 +++++++++++++++++++++----------- src/simulation/elements/PRTI.cpp | 5 +-- src/simulation/elements/PRTO.cpp | 5 +-- src/simulation/orbitalparts.h | 33 ++++++++++++++++++ 29 files changed, 165 insertions(+), 123 deletions(-) create mode 100644 src/simulation/orbitalparts.h diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 569d8df26..7b52489ee 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -7,6 +7,7 @@ #include "simulation/ElementClasses.h" #include "simulation/Air.h" #include "simulation/gravity/Gravity.h" +#include "simulation/orbitalparts.h" #include std::unique_ptr Renderer::WallIcon(int wallID, Vec2 size) @@ -174,12 +175,17 @@ void Renderer::render_parts() auto &sd = SimulationData::CRef(); auto &elements = sd.elements; auto &graphicscache = sd.graphicscache; + GraphicsFuncContext gfctx; + gfctx.ren = this; + gfctx.sim = sim; + gfctx.rng.seed(rng()); + gfctx.pipeSubcallCpart = nullptr; + gfctx.pipeSubcallTpart = nullptr; int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y; int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0}; - Particle * parts; if(!sim) return; - parts = sim->parts; + auto *parts = sim->parts; if (gridSize)//draws the grid { for (ny=0; nyparts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb); //That's a lot of args, a struct might be better - if (makeReady && useGraphicsFunction) + auto *graphics = elements[t].Graphics; + auto makeReady = !graphics || graphics(gfctx, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb); //That's a lot of args, a struct might be better + if (makeReady && sim->useLuaCallbacks) { - // I sure hope we locked sd.elementGraphicsMx exclusively + // useLuaCallbacks is true so we locked sd.elementGraphicsMx exclusively auto &wgraphicscache = SimulationData::Ref().graphicscache; wgraphicscache[t].isready = 1; wgraphicscache[t].pixel_mode = pixel_mode; @@ -437,7 +443,7 @@ void Renderer::render_parts() if(pixel_mode & PSPEC_STICKMAN) { int legr, legg, legb; - playerst *cplayer; + const playerst *cplayer; if(t==PT_STKM) cplayer = &sim->player; else if(t==PT_STKM2) @@ -625,7 +631,7 @@ void Renderer::render_parts() } if(pixel_mode & PMODE_SPARK) { - auto flicker = float(rng()%20); + auto flicker = float(gfctx.rng()%20); auto gradv = 4*sim->parts[i].life + flicker; for (x = 0; gradv>0.5; x++) { auto col = RGBA( @@ -642,7 +648,7 @@ void Renderer::render_parts() } if(pixel_mode & PMODE_FLARE) { - auto flicker = float(rng()%20); + auto flicker = float(gfctx.rng()%20); auto gradv = flicker + fabs(parts[i].vx)*17 + fabs(sim->parts[i].vy)*17; BlendPixel({ nx, ny }, RGBA(colr, colg, colb, int((gradv*4)>255?255:(gradv*4)) )); BlendPixel({ nx+1, ny }, RGBA(colr, colg, colb,int( (gradv*2)>255?255:(gradv*2)) )); @@ -664,7 +670,7 @@ void Renderer::render_parts() } if(pixel_mode & PMODE_LFLARE) { - auto flicker = float(rng()%20); + auto flicker = float(gfctx.rng()%20); auto gradv = flicker + fabs(parts[i].vx)*17 + fabs(parts[i].vy)*17; BlendPixel({ nx, ny }, RGBA(colr, colg, colb, int((gradv*4)>255?255:(gradv*4)) )); BlendPixel({ nx+1, ny }, RGBA(colr, colg, colb, int((gradv*2)>255?255:(gradv*2)) )); @@ -691,7 +697,7 @@ void Renderer::render_parts() int r; float drad = 0.0f; float ddist = 0.0f; - sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); for (r = 0; r < 4; r++) { ddist = ((float)orbd[r])/16.0f; drad = (TPT_PI_FLT * ((float)orbl[r]) / 180.0f)*1.41f; @@ -708,7 +714,7 @@ void Renderer::render_parts() int r; float drad = 0.0f; float ddist = 0.0f; - sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); for (r = 0; r < 4; r++) { ddist = ((float)orbd[r])/16.0f; drad = (TPT_PI_FLT * ((float)orbl[r]) / 180.0f)*1.41f; diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index 98efee53a..35f90bbc4 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -13,6 +13,17 @@ class RenderPreset; class Simulation; +class Renderer; +struct Particle; + +struct GraphicsFuncContext +{ + const Renderer *ren; + const Simulation *sim; + RNG rng; + const Particle *pipeSubcallCpart; + Particle *pipeSubcallTpart; +}; int HeatToColour(float temp); @@ -43,7 +54,7 @@ public: RNG rng; - Simulation * sim; + const Simulation *sim; std::vector render_modes; unsigned int render_mode; @@ -125,7 +136,7 @@ public: static std::unique_ptr WallIcon(int wallID, Vec2 size); - Renderer(Simulation * sim); + Renderer(Simulation *newSim); #define RENDERER_TABLE(name) \ static std::vector> name; \ @@ -144,8 +155,6 @@ public: #undef RENDERER_TABLE static void PopulateTables(); - bool useGraphicsFunction = false; - private: int gridSize; }; diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index 43f892732..97e4287e4 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -224,8 +224,8 @@ void Renderer::PopulateTables() } } -Renderer::Renderer(Simulation * sim): - sim(NULL), +Renderer::Renderer(Simulation *newSim): + sim(newSim), render_mode(0), colour_mode(0), display_mode(0), @@ -246,8 +246,6 @@ Renderer::Renderer(Simulation * sim): { PopulateTables(); - this->sim = sim; - memset(fire_r, 0, sizeof(fire_r)); memset(fire_g, 0, sizeof(fire_g)); memset(fire_b, 0, sizeof(fire_b)); diff --git a/src/gui/game/GOLTool.cpp b/src/gui/game/GOLTool.cpp index c44a48b58..b5f273816 100644 --- a/src/gui/game/GOLTool.cpp +++ b/src/gui/game/GOLTool.cpp @@ -23,14 +23,13 @@ class GOLWindow: public ui::Window ui::Button *highColourButton, *lowColourButton; ui::Textbox *nameField, *ruleField; GameModel &gameModel; - Simulation *sim; int toolSelection; void updateGradient(); void validate(); public: - GOLWindow(GameModel &gameModel, Simulation *sim, int toolSelection, int rule, RGB colour1, RGB colour2); + GOLWindow(GameModel &gameModel, int toolSelection, int rule, RGB colour1, RGB colour2); virtual ~GOLWindow() {} @@ -39,12 +38,11 @@ public: void OnTryExit(ExitMethod method) override; }; -GOLWindow::GOLWindow(GameModel &gameModel_, Simulation *sim_, int toolSelection, int rule, RGB colour1, RGB colour2): +GOLWindow::GOLWindow(GameModel &gameModel_, int toolSelection, int rule, RGB colour1, RGB colour2): ui::Window(ui::Point(-1, -1), ui::Point(200, 108)), highColour(colour1.WithAlpha(0xFF)), lowColour(colour2.WithAlpha(0xFF)), gameModel(gameModel_), - sim(sim_), toolSelection(toolSelection) { highColour.Alpha = 255; @@ -205,5 +203,5 @@ void GOLWindow::OnDraw() void GOLTool::OpenWindow(Simulation *sim, int toolSelection, int rule, RGB colour1, RGB colour2) { - new GOLWindow(gameModel, sim, toolSelection, rule, colour1, colour2); + new GOLWindow(gameModel, toolSelection, rule, colour1, colour2); } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 92b93904d..f95deec30 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -56,8 +56,8 @@ GameModel::GameModel(): decoSpace(0) { sim = new Simulation(); + sim->useLuaCallbacks = true; ren = new Renderer(sim); - ren->useGraphicsFunction = true; activeTools = regularToolset; diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index b3e24c9bf..8cc3a1bdb 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -3491,11 +3491,21 @@ static int luaUpdateWrapper(UPDATE_FUNC_ARGS) static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS) { + if (!gfctx.sim->useLuaCallbacks) + { + return Element::defaultGraphics(GRAPHICS_FUNC_SUBCALL_ARGS); + } auto *luacon_ci = static_cast(commandInterface); if (lua_gr_func[cpart->type]) { + auto *pipeSubcallWcpart = gfctx.pipeSubcallCpart ? luacon_sim->parts + (gfctx.pipeSubcallCpart - gfctx.sim->parts) : nullptr; + if (pipeSubcallWcpart) + { + std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart); + cpart = pipeSubcallWcpart; + } int cache = 0, callret; - int i = cpart - ren->sim->parts; // pointer arithmetic be like + int i = cpart - gfctx.sim->parts; // pointer arithmetic be like lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, lua_gr_func[cpart->type]); lua_pushinteger(luacon_ci->l, i); lua_pushinteger(luacon_ci->l, *colr); @@ -3531,6 +3541,10 @@ static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS) } lua_pop(luacon_ci->l, 10); } + if (pipeSubcallWcpart) + { + std::swap(*pipeSubcallWcpart, *gfctx.pipeSubcallTpart); + } return cache; } return 0; diff --git a/src/simulation/Element.h b/src/simulation/Element.h index 791984737..d2026decf 100644 --- a/src/simulation/Element.h +++ b/src/simulation/Element.h @@ -8,6 +8,7 @@ class Simulation; class Renderer; +struct GraphicsFuncContext; class VideoBuffer; struct Particle; class Element diff --git a/src/simulation/ElementDefs.h b/src/simulation/ElementDefs.h index c808d1fc4..285119e7d 100644 --- a/src/simulation/ElementDefs.h +++ b/src/simulation/ElementDefs.h @@ -42,8 +42,8 @@ constexpr auto FLAG_PHOTDECO = UINT32_C(0x00000008); // compatibility with #define UPDATE_FUNC_ARGS Simulation* sim, int i, int x, int y, int surround_space, int nt, Particle *parts, int pmap[YRES][XRES] #define UPDATE_FUNC_SUBCALL_ARGS sim, i, x, y, surround_space, nt, parts, pmap -#define GRAPHICS_FUNC_ARGS Renderer * ren, Particle *cpart, int nx, int ny, int *pixel_mode, int* cola, int *colr, int *colg, int *colb, int *firea, int *firer, int *fireg, int *fireb -#define GRAPHICS_FUNC_SUBCALL_ARGS ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb +#define GRAPHICS_FUNC_ARGS GraphicsFuncContext &gfctx, const Particle *cpart, int nx, int ny, int *pixel_mode, int* cola, int *colr, int *colg, int *colb, int *firea, int *firer, int *fireg, int *fireb +#define GRAPHICS_FUNC_SUBCALL_ARGS gfctx, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb #define ELEMENT_CREATE_FUNC_ARGS Simulation *sim, int i, int x, int y, int t, int v diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index 65c6f73ee..3f938d2b8 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -8,13 +8,16 @@ #include "Simulation.h" #include "SimulationData.h" -SaveRenderer::SaveRenderer(){ - sim = new Simulation(); - ren = new Renderer(sim); +SaveRenderer::SaveRenderer() +{ + sim = std::make_unique(); + ren = std::make_unique(sim.get()); ren->decorations_enable = true; ren->blackDecorations = true; } +SaveRenderer::~SaveRenderer() = default; + std::pair, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) { // this function usually runs on a thread different from where element info in SimulationData may be written, so we acquire a read-only lock on it @@ -58,9 +61,3 @@ std::pair, MissingElements> SaveRenderer::Render(co return { std::move(tempThumb), missingElementTypes }; } - -SaveRenderer::~SaveRenderer() -{ - delete ren; - delete sim; -} diff --git a/src/simulation/SaveRenderer.h b/src/simulation/SaveRenderer.h index 65a8ac4ab..dc913e1d9 100644 --- a/src/simulation/SaveRenderer.h +++ b/src/simulation/SaveRenderer.h @@ -9,16 +9,17 @@ class GameSave; class VideoBuffer; -class Graphics; class Simulation; class Renderer; -class SaveRenderer: public ExplicitSingleton { - Simulation * sim; - Renderer * ren; +class SaveRenderer: public ExplicitSingleton +{ + std::unique_ptr sim; + std::unique_ptr ren; std::mutex renderMutex; + public: SaveRenderer(); + ~SaveRenderer(); std::pair, MissingElements> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); - virtual ~SaveRenderer(); }; diff --git a/src/simulation/Sign.cpp b/src/simulation/Sign.cpp index 590bd21ff..bc1c65b60 100644 --- a/src/simulation/Sign.cpp +++ b/src/simulation/Sign.cpp @@ -12,7 +12,7 @@ sign::sign(String text_, int x_, int y_, Justification justification_): { } -String sign::getDisplayText(Simulation *sim, int &x0, int &y0, int &w, int &h, bool colorize, bool *v95) const +String sign::getDisplayText(const Simulation *sim, int &x0, int &y0, int &w, int &h, bool colorize, bool *v95) const { auto &sd = SimulationData::CRef(); String drawable_text; diff --git a/src/simulation/Sign.h b/src/simulation/Sign.h index 211d46437..0d4f514ac 100644 --- a/src/simulation/Sign.h +++ b/src/simulation/Sign.h @@ -28,6 +28,6 @@ struct sign String text; sign(String text_, int x_, int y_, Justification justification_); - String getDisplayText(Simulation *sim, int &x, int &y, int &w, int &h, bool colorize = true, bool *v95 = nullptr) const; + String getDisplayText(const Simulation *sim, int &x, int &y, int &w, int &h, bool colorize = true, bool *v95 = nullptr) const; std::pair split() const; }; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 7416bb684..494ac05af 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -874,38 +874,6 @@ void Simulation::CreateLine(int x1, int y1, int x2, int y2, int c) } } -void Simulation::orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]) -{ - resblock1[0] = (block1&0x000000FF); - resblock1[1] = (block1&0x0000FF00)>>8; - resblock1[2] = (block1&0x00FF0000)>>16; - resblock1[3] = (block1&0xFF000000)>>24; - - resblock2[0] = (block2&0x000000FF); - resblock2[1] = (block2&0x0000FF00)>>8; - resblock2[2] = (block2&0x00FF0000)>>16; - resblock2[3] = (block2&0xFF000000)>>24; -} - -void Simulation::orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]) -{ - int block1tmp = 0; - int block2tmp = 0; - - block1tmp = (resblock1[0]&0xFF); - block1tmp |= (resblock1[1]&0xFF)<<8; - block1tmp |= (resblock1[2]&0xFF)<<16; - block1tmp |= (resblock1[3]&0xFF)<<24; - - block2tmp = (resblock2[0]&0xFF); - block2tmp |= (resblock2[1]&0xFF)<<8; - block2tmp |= (resblock2[2]&0xFF)<<16; - block2tmp |= (resblock2[3]&0xFF)<<24; - - *block1 = block1tmp; - *block2 = block2tmp; -} - inline int Simulation::is_wire(int x, int y) { return bmap[y][x]==WL_DETECT || bmap[y][x]==WL_EWALL || bmap[y][x]==WL_ALLOWLIQUID || bmap[y][x]==WL_WALLELEC || bmap[y][x]==WL_ALLOWALLELEC || bmap[y][x]==WL_EHOLE || bmap[y][x]==WL_STASIS; diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index c9530f041..21f0fc82c 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -201,8 +201,6 @@ public: void GetGravityField(int x, int y, float particleGrav, float newtonGrav, float & pGravX, float & pGravY); - void orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]); - void orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]); int get_wavelength_bin(int *wm); struct GetNormalResult { @@ -217,6 +215,8 @@ public: Simulation(); ~Simulation(); + bool useLuaCallbacks = false; + private: CoordStack& getCoordStackSingleton(); }; diff --git a/src/simulation/elements/CRAY.cpp b/src/simulation/elements/CRAY.cpp index 878ffe5b5..1e5f86108 100644 --- a/src/simulation/elements/CRAY.cpp +++ b/src/simulation/elements/CRAY.cpp @@ -116,7 +116,6 @@ static int update(UPDATE_FUNC_ARGS) colored = 0xFF000000; else if (parts[ID(r)].tmp==0) { - int Element_FILT_getWavelengths(Particle* cpart); colored = wavelengthToDecoColour(Element_FILT_getWavelengths(&parts[ID(r)])); } else if (colored==0xFF000000) diff --git a/src/simulation/elements/EMBR.cpp b/src/simulation/elements/EMBR.cpp index 70b2cba1e..4edaa1ddd 100644 --- a/src/simulation/elements/EMBR.cpp +++ b/src/simulation/elements/EMBR.cpp @@ -100,9 +100,9 @@ static int graphics(GRAPHICS_FUNC_ARGS) } bool deco = false; - if (ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000)) + if (gfctx.ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000)) { - if (!ren->blackDecorations) // if blackDecorations is off, always show deco + if (!gfctx.ren->blackDecorations) // if blackDecorations is off, always show deco deco = true; else if (((cpart->dcolour>>24)&0xFF) >= 250 && ((cpart->dcolour>>16)&0xFF) <= 5 && ((cpart->dcolour>>8)&0xFF) <= 5 && ((cpart->dcolour)&0xFF) <= 5) // else only render black deco deco = true; diff --git a/src/simulation/elements/EXOT.cpp b/src/simulation/elements/EXOT.cpp index c4d630f3e..5b9d7592b 100644 --- a/src/simulation/elements/EXOT.cpp +++ b/src/simulation/elements/EXOT.cpp @@ -196,7 +196,7 @@ static int graphics(GRAPHICS_FUNC_ARGS) auto c = cpart->tmp2; if (cpart->life < 1001) { - if (ren->rng.chance(cpart->tmp2 - 1, 1000)) + if (gfctx.rng.chance(cpart->tmp2 - 1, 1000)) { float frequency = 0.04045f; *colr = int(sin(frequency*c + 4) * 127 + 150); diff --git a/src/simulation/elements/FILT.cpp b/src/simulation/elements/FILT.cpp index d3b3209de..c78e23b33 100644 --- a/src/simulation/elements/FILT.cpp +++ b/src/simulation/elements/FILT.cpp @@ -3,7 +3,6 @@ static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); -int Element_FILT_getWavelengths(Particle* cpart); void Element::Element_FILT() { @@ -135,7 +134,7 @@ int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origW } } -int Element_FILT_getWavelengths(Particle* cpart) +int Element_FILT_getWavelengths(const Particle* cpart) { if (cpart->ctype&0x3FFFFFFF) { diff --git a/src/simulation/elements/GLOW.cpp b/src/simulation/elements/GLOW.cpp index 7df7367c4..f9e986c41 100644 --- a/src/simulation/elements/GLOW.cpp +++ b/src/simulation/elements/GLOW.cpp @@ -90,7 +90,7 @@ static int graphics(GRAPHICS_FUNC_ARGS) *colg = int(restrict_flt(64.0f+cpart->ctype, 0, 255)); *colb = int(restrict_flt(64.0f+cpart->tmp, 0, 255)); - int rng = ren->rng.between(1, 32); // + int rng = gfctx.rng.between(1, 32); // if(((*colr) + (*colg) + (*colb)) > (256 + rng)) { *colr -= 54; *colg -= 54; diff --git a/src/simulation/elements/GOLD.cpp b/src/simulation/elements/GOLD.cpp index cab7bfa63..e45dd2ff9 100644 --- a/src/simulation/elements/GOLD.cpp +++ b/src/simulation/elements/GOLD.cpp @@ -99,7 +99,7 @@ static int update(UPDATE_FUNC_ARGS) static int graphics(GRAPHICS_FUNC_ARGS) { - int rndstore = ren->rng.gen(); + int rndstore = gfctx.rng.gen(); *colr += (rndstore % 10) - 5; rndstore >>= 4; *colg += (rndstore % 10)- 5; diff --git a/src/simulation/elements/GRAV.cpp b/src/simulation/elements/GRAV.cpp index cd818851d..c36d4687a 100644 --- a/src/simulation/elements/GRAV.cpp +++ b/src/simulation/elements/GRAV.cpp @@ -63,12 +63,12 @@ static int graphics(GRAPHICS_FUNC_ARGS) { int GRAV_R, GRAV_B, GRAV_G, GRAV_R2, GRAV_B2, GRAV_G2; - GRAV_R = std::abs((ren->sim->currentTick%120)-60); - GRAV_G = std::abs(((ren->sim->currentTick+60)%120)-60); - GRAV_B = std::abs(((ren->sim->currentTick+120)%120)-60); - GRAV_R2 = std::abs((ren->sim->currentTick%60)-30); - GRAV_G2 = std::abs(((ren->sim->currentTick+30)%60)-30); - GRAV_B2 = std::abs(((ren->sim->currentTick+60)%60)-30); + GRAV_R = std::abs((gfctx.sim->currentTick%120)-60); + GRAV_G = std::abs(((gfctx.sim->currentTick+60)%120)-60); + GRAV_B = std::abs(((gfctx.sim->currentTick+120)%120)-60); + GRAV_R2 = std::abs((gfctx.sim->currentTick%60)-30); + GRAV_G2 = std::abs(((gfctx.sim->currentTick+30)%60)-30); + GRAV_B2 = std::abs(((gfctx.sim->currentTick+60)%60)-30); *colr = 20; diff --git a/src/simulation/elements/LCRY.cpp b/src/simulation/elements/LCRY.cpp index 7c0b5d6d6..08336aa95 100644 --- a/src/simulation/elements/LCRY.cpp +++ b/src/simulation/elements/LCRY.cpp @@ -107,9 +107,9 @@ static int update(UPDATE_FUNC_ARGS) static int graphics(GRAPHICS_FUNC_ARGS) { bool deco = false; - if (ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000)) + if (gfctx.ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000)) { - if (!ren->blackDecorations) // if blackDecorations is off, always show deco + if (!gfctx.ren->blackDecorations) // if blackDecorations is off, always show deco deco = true; else if(((cpart->dcolour>>24)&0xFF) >= 250 && ((cpart->dcolour>>16)&0xFF) <= 5 && ((cpart->dcolour>>8)&0xFF) <= 5 && ((cpart->dcolour)&0xFF) <= 5) // else only render black deco deco = true; diff --git a/src/simulation/elements/LDTC.cpp b/src/simulation/elements/LDTC.cpp index 850f57635..2307159a1 100644 --- a/src/simulation/elements/LDTC.cpp +++ b/src/simulation/elements/LDTC.cpp @@ -151,7 +151,6 @@ static int update(UPDATE_FUNC_ARGS) continue; int nx = x + rx, ny = y + ry; - int Element_FILT_getWavelengths(Particle* cpart); int photonWl = TYP(rr) == PT_FILT ? Element_FILT_getWavelengths(&parts[ID(rr)]) : parts[ID(rr)].ctype; diff --git a/src/simulation/elements/LIFE.cpp b/src/simulation/elements/LIFE.cpp index fda53089a..411f4096e 100644 --- a/src/simulation/elements/LIFE.cpp +++ b/src/simulation/elements/LIFE.cpp @@ -58,10 +58,10 @@ static int graphics(GRAPHICS_FUNC_ARGS) colour1 = 0xFFFFFF_rgb; } auto ruleset = cpart->ctype; - bool renderDeco = !ren->blackDecorations; + bool renderDeco = !gfctx.ren->blackDecorations; if (ruleset >= 0 && ruleset < NGOL) { - if (!renderDeco || !ren->decorations_enable) + if (!renderDeco || !gfctx.ren->decorations_enable) { colour1 = builtinGol[ruleset].colour; colour2 = builtinGol[ruleset].colour2; diff --git a/src/simulation/elements/LITH.cpp b/src/simulation/elements/LITH.cpp index 4ace0e832..7a647d2c9 100644 --- a/src/simulation/elements/LITH.cpp +++ b/src/simulation/elements/LITH.cpp @@ -257,7 +257,7 @@ static int graphics(GRAPHICS_FUNC_ARGS) // Charged lith else if (cpart->ctype > 0) { - int mult = ren->rng.between(cpart->ctype / 3, cpart->ctype) / 15; + int mult = gfctx.rng.between(cpart->ctype / 3, cpart->ctype) / 15; mult = std::min(6, mult); *colr -= 30 * mult; *colb += 20 * mult; diff --git a/src/simulation/elements/PIPE.cpp b/src/simulation/elements/PIPE.cpp index 51df18f27..51ef0d410 100644 --- a/src/simulation/elements/PIPE.cpp +++ b/src/simulation/elements/PIPE.cpp @@ -4,6 +4,7 @@ extern const std::array, 8> Element_PIPE_offsets; void Element_PIPE_transformPatchOffsets(Particle &part, const std::array &offsetMap); int Element_PIPE_update(UPDATE_FUNC_ARGS); int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS); +static void props_pipe_to_part(const Particle *pipe, Particle *part, bool STOR); void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); static void transfer_part_to_pipe(Particle *part, Particle *pipe); static void transfer_pipe_to_pipe(Particle *src, Particle *dest, bool STOR); @@ -368,32 +369,38 @@ int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) } else { - // Temp particle used for graphics. - Particle tpart = *cpart; - - // Emulate the graphics of stored particle. - memset(cpart, 0, sizeof(Particle)); - cpart->type = t; - cpart->temp = tpart.temp; - cpart->life = tpart.tmp2; - cpart->tmp = tpart.tmp3; - cpart->ctype = tpart.tmp4; - + // We emulate the graphics of the stored particle. We need a const Particle *cpart to pass to the graphics function, + // but we don't have a Particle that is populated the way the graphics function expects, so we construct a temporary + // one and present that to it. + // + // Native graphics functions are well-behaved and use the cpart we give them, no questions asked, so we can just have + // the Particle on stack. Swapping the pointers in cpart with tpart takes care of passing the particle on stack to the + // native graphics function. Lua graphics functions are more complicated to appease: they access particle data through the + // particle ID, so not only do we have to give them a correctly populated Particle, it also has to be somewhere in Simulation. + // luaGraphicsWrapper takes care of this. RGB colour = elements[t].Colour; *colr = colour.Red; *colg = colour.Green; *colb = colour.Blue; - if (elements[t].Graphics) + auto *graphics = elements[t].Graphics; + if (graphics) { - (*(elements[t].Graphics))(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); + Particle tpart; + props_pipe_to_part(cpart, &tpart, false); + auto *prevPipeSubcallCpart = gfctx.pipeSubcallCpart; + auto *prevPipeSubcallTpart = gfctx.pipeSubcallTpart; + gfctx.pipeSubcallCpart = cpart; + gfctx.pipeSubcallTpart = &tpart; + cpart = gfctx.pipeSubcallTpart; + graphics(GRAPHICS_FUNC_SUBCALL_ARGS); + cpart = gfctx.pipeSubcallCpart; + gfctx.pipeSubcallCpart = prevPipeSubcallCpart; + gfctx.pipeSubcallTpart = prevPipeSubcallTpart; } else { - Element::defaultGraphics(ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb); + Element::defaultGraphics(GRAPHICS_FUNC_SUBCALL_ARGS); } - - // Restore original particle data. - *cpart = tpart; } } else @@ -422,7 +429,7 @@ int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS) return 0; } -void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR) +static void props_pipe_to_part(const Particle *pipe, Particle *part, bool STOR) { auto &sd = SimulationData::CRef(); auto &elements = sd.elements; @@ -431,12 +438,10 @@ void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Partic if (STOR) { part->type = TYP(pipe->tmp); - pipe->tmp = 0; } else { part->type = TYP(pipe->ctype); - pipe->ctype = 0; } part->temp = pipe->temp; part->life = pipe->tmp2; @@ -453,6 +458,19 @@ void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Partic part->dcolour = 0; } +void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR) +{ + props_pipe_to_part(pipe, part, STOR); + if (STOR) + { + pipe->tmp = 0; + } + else + { + pipe->ctype = 0; + } +} + static void transfer_part_to_pipe(Particle *part, Particle *pipe) { pipe->ctype = part->type; diff --git a/src/simulation/elements/PRTI.cpp b/src/simulation/elements/PRTI.cpp index 53869e43e..b41a26e8a 100644 --- a/src/simulation/elements/PRTI.cpp +++ b/src/simulation/elements/PRTI.cpp @@ -1,4 +1,5 @@ #include "simulation/ElementCommon.h" +#include "simulation/orbitalparts.h" void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); static int update(UPDATE_FUNC_ARGS); @@ -123,7 +124,7 @@ static int update(UPDATE_FUNC_ARGS) int orbl[4] = {0, 0, 0, 0}; //Orbital locations if (!sim->parts[i].life) parts[i].life = sim->rng.gen(); if (!sim->parts[i].ctype) parts[i].ctype = sim->rng.gen(); - sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); for (int r = 0; r < 4; r++) { if (orbd[r]>1) { orbd[r] -= 12; @@ -139,7 +140,7 @@ static int update(UPDATE_FUNC_ARGS) orbl[r] = sim->rng.between(0, 254); } } - sim->orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); + orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); } else { parts[i].life = 0; parts[i].ctype = 0; diff --git a/src/simulation/elements/PRTO.cpp b/src/simulation/elements/PRTO.cpp index bf9b1e485..9924417a9 100644 --- a/src/simulation/elements/PRTO.cpp +++ b/src/simulation/elements/PRTO.cpp @@ -1,4 +1,5 @@ #include "simulation/ElementCommon.h" +#include "simulation/orbitalparts.h" static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); @@ -144,7 +145,7 @@ static int update(UPDATE_FUNC_ARGS) int orbl[4] = {0, 0, 0, 0}; //Orbital locations if (!sim->parts[i].life) parts[i].life = sim->rng.gen(); if (!sim->parts[i].ctype) parts[i].ctype = sim->rng.gen(); - sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); for (auto r = 0; r < 4; r++) { if (orbd[r]<254) @@ -166,7 +167,7 @@ static int update(UPDATE_FUNC_ARGS) orbl[r] = sim->rng.between(0, 254); } } - sim->orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); + orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl); } else { diff --git a/src/simulation/orbitalparts.h b/src/simulation/orbitalparts.h new file mode 100644 index 000000000..b5ba2be35 --- /dev/null +++ b/src/simulation/orbitalparts.h @@ -0,0 +1,33 @@ +#pragma once + +inline void orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]) +{ + resblock1[0] = (block1&0x000000FF); + resblock1[1] = (block1&0x0000FF00)>>8; + resblock1[2] = (block1&0x00FF0000)>>16; + resblock1[3] = (block1&0xFF000000)>>24; + + resblock2[0] = (block2&0x000000FF); + resblock2[1] = (block2&0x0000FF00)>>8; + resblock2[2] = (block2&0x00FF0000)>>16; + resblock2[3] = (block2&0xFF000000)>>24; +} + +inline void orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]) +{ + int block1tmp = 0; + int block2tmp = 0; + + block1tmp = (resblock1[0]&0xFF); + block1tmp |= (resblock1[1]&0xFF)<<8; + block1tmp |= (resblock1[2]&0xFF)<<16; + block1tmp |= (resblock1[3]&0xFF)<<24; + + block2tmp = (resblock2[0]&0xFF); + block2tmp |= (resblock2[1]&0xFF)<<8; + block2tmp |= (resblock2[2]&0xFF)<<16; + block2tmp |= (resblock2[3]&0xFF)<<24; + + *block1 = block1tmp; + *block2 = block2tmp; +} From ca6c67c16c02043b4c12229e4a933c77e340d25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 12:31:23 +0100 Subject: [PATCH 07/12] Factor functions shared between elements into headers The signature duplication was getting out of hand; too easy to get wrong. --- src/client/GameSave.cpp | 4 +--- src/gui/game/GameController.cpp | 2 +- src/simulation/Simulation.cpp | 17 +++++------------ src/simulation/elements/ARAY.cpp | 2 +- src/simulation/elements/BCOL.cpp | 4 +--- src/simulation/elements/BIZR.cpp | 4 +--- src/simulation/elements/BIZR.h | 5 +++++ src/simulation/elements/BIZRG.cpp | 4 +--- src/simulation/elements/BIZRS.cpp | 4 +--- src/simulation/elements/BVBR.cpp | 4 +--- src/simulation/elements/COAL.cpp | 4 +--- src/simulation/elements/COAL.h | 5 +++++ src/simulation/elements/CRAY.cpp | 1 + src/simulation/elements/EMP.h | 4 ++++ src/simulation/elements/ETRD.h | 4 ++++ src/simulation/elements/FIGH.cpp | 7 +------ src/simulation/elements/FILT.cpp | 2 +- src/simulation/elements/FILT.h | 5 +++++ src/simulation/elements/FIRE.cpp | 2 +- src/simulation/elements/FIRE.h | 4 ++++ src/simulation/elements/LAVA.cpp | 2 +- src/simulation/elements/LDTC.cpp | 2 +- src/simulation/elements/LOLZ.h | 7 +++++++ src/simulation/elements/NEUT.cpp | 2 +- src/simulation/elements/NTCT.cpp | 3 +-- src/simulation/elements/NTCT.h | 4 ++++ src/simulation/elements/PBCN.cpp | 2 +- src/simulation/elements/PCLN.cpp | 2 +- src/simulation/elements/PCLN.h | 4 ++++ src/simulation/elements/PHOT.cpp | 4 ++-- src/simulation/elements/PIPE.cpp | 8 ++------ src/simulation/elements/PIPE.h | 11 +++++++++++ src/simulation/elements/PLSM.cpp | 2 +- src/simulation/elements/PPIP.cpp | 4 +--- src/simulation/elements/PQRT.cpp | 3 +-- src/simulation/elements/PRTI.cpp | 4 ++-- src/simulation/elements/QRTZ.cpp | 3 +-- src/simulation/elements/QRTZ.h | 5 +++++ src/simulation/elements/RFGL.cpp | 3 +-- src/simulation/elements/RFRG.cpp | 3 +-- src/simulation/elements/RFRG.h | 4 ++++ src/simulation/elements/SOAP.h | 4 ++++ src/simulation/elements/SPRK.cpp | 8 ++++---- src/simulation/elements/STKM.cpp | 6 +----- src/simulation/elements/STKM.h | 12 ++++++++++++ src/simulation/elements/STKM2.cpp | 4 +--- src/simulation/elements/STOR.cpp | 2 +- src/simulation/elements/VIBR.cpp | 4 +--- src/simulation/elements/VIBR.h | 5 +++++ src/simulation/elements/VIRS.cpp | 2 +- src/simulation/elements/VIRS.h | 4 ++++ src/simulation/elements/VRSG.cpp | 2 +- src/simulation/elements/VRSS.cpp | 2 +- 53 files changed, 134 insertions(+), 91 deletions(-) create mode 100644 src/simulation/elements/BIZR.h create mode 100644 src/simulation/elements/COAL.h create mode 100644 src/simulation/elements/EMP.h create mode 100644 src/simulation/elements/ETRD.h create mode 100644 src/simulation/elements/FILT.h create mode 100644 src/simulation/elements/FIRE.h create mode 100644 src/simulation/elements/LOLZ.h create mode 100644 src/simulation/elements/NTCT.h create mode 100644 src/simulation/elements/PCLN.h create mode 100644 src/simulation/elements/PIPE.h create mode 100644 src/simulation/elements/QRTZ.h create mode 100644 src/simulation/elements/RFRG.h create mode 100644 src/simulation/elements/SOAP.h create mode 100644 src/simulation/elements/STKM.h create mode 100644 src/simulation/elements/VIBR.h create mode 100644 src/simulation/elements/VIRS.h diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 3d08d48ca..f506a0485 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -3,6 +3,7 @@ #include "Format.h" #include "simulation/Simulation.h" #include "simulation/ElementClasses.h" +#include "simulation/elements/PIPE.h" #include "common/tpt-compat.h" #include "bson/BSON.h" #include "graphics/Renderer.h" @@ -114,9 +115,6 @@ std::pair> GameSave::Serialise() const return { false, {} }; } -extern const std::array, 8> Element_PIPE_offsets; -void Element_PIPE_transformPatchOffsets(Particle &part, const std::array &offsetMap); - void GameSave::Transform(Mat2 transform, Vec2 nudge) { // undo translation by rotation diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index 33b5640a4..d60216018 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -31,6 +31,7 @@ #include "simulation/Simulation.h" #include "simulation/SimulationData.h" #include "simulation/Snapshot.h" +#include "simulation/elements/STKM.h" #include "gui/dialogues/ErrorMessage.h" #include "gui/dialogues/InformationMessage.h" @@ -881,7 +882,6 @@ void GameController::Update() rightSelected = sr; } - void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element); if (!sim->player.spwn) Element_STKM_set_element(sim, &sim->player, rightSelected); if (!sim->player2.spwn) diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 494ac05af..a48b45527 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -9,15 +9,14 @@ #include "common/tpt-rand.h" #include "common/tpt-thread-local.h" #include "gui/game/Brush.h" +#include "elements/EMP.h" +#include "elements/LOLZ.h" +#include "elements/STKM.h" +#include "elements/PIPE.h" +#include "elements/FILT.h" #include #include -extern int Element_PPIP_ppip_changed; -extern int Element_LOLZ_RuleTable[9][9]; -extern int Element_LOLZ_lolz[XRES/9][YRES/9]; -extern int Element_LOVE_RuleTable[9][9]; -extern int Element_LOVE_love[XRES/9][YRES/9]; - static float remainder_p(float x, float y) { return std::fmod(x, y) + (x>=0 ? 0 : y); @@ -127,7 +126,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec { continue; } - bool Element_FIGH_CanAlloc(Simulation *sim); if (tempPart.type == PT_FIGH && !Element_FIGH_CanAlloc(this)) { continue; @@ -159,7 +157,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec elementCount[tempPart.type]++; - void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i); switch (parts[i].type) { case PT_STKM: @@ -200,7 +197,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec case PT_FIGH: { unsigned int oldTmp = parts[i].tmp; - int Element_FIGH_Alloc(Simulation *sim); parts[i].tmp = Element_FIGH_Alloc(this); if (parts[i].tmp >= 0) { @@ -212,7 +208,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec parts[i].ctype = 0; } fighters[parts[i].tmp].elem = PT_DUST; - void Element_FIGH_NewFighter(Simulation *sim, int fighterID, int i, int elem); Element_FIGH_NewFighter(this, parts[i].tmp, i, parts[i].ctype); if (fan) fighters[parts[i].tmp].fan = true; @@ -1262,7 +1257,6 @@ int Simulation::try_move(int i, int x, int y, int nx, int ny) return 0; } - int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); if (e == 2) //if occupy same space { switch (parts[i].type) @@ -3922,7 +3916,6 @@ void Simulation::AfterSim() if (emp_trigger_count) { // pitiful attempt at trying to keep code relating to a given element in the same file - void Element_EMP_Trigger(Simulation *sim, int triggerCount); Element_EMP_Trigger(this, emp_trigger_count); emp_trigger_count = 0; } diff --git a/src/simulation/elements/ARAY.cpp b/src/simulation/elements/ARAY.cpp index e60cee4ee..e101e3aac 100644 --- a/src/simulation/elements/ARAY.cpp +++ b/src/simulation/elements/ARAY.cpp @@ -1,4 +1,5 @@ #include "simulation/ElementCommon.h" +#include "FILT.h" static int update(UPDATE_FUNC_ARGS); @@ -130,7 +131,6 @@ static int update(UPDATE_FUNC_ARGS) { if (parts[r].tmp != 6) { - int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); colored = Element_FILT_interactWavelengths(sim, &parts[r], colored); if (!colored) break; diff --git a/src/simulation/elements/BCOL.cpp b/src/simulation/elements/BCOL.cpp index f950aeb7a..c1b5d0a76 100644 --- a/src/simulation/elements/BCOL.cpp +++ b/src/simulation/elements/BCOL.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_COAL_update(UPDATE_FUNC_ARGS); -int Element_COAL_graphics(GRAPHICS_FUNC_ARGS); +#include "COAL.h" void Element::Element_BCOL() { diff --git a/src/simulation/elements/BIZR.cpp b/src/simulation/elements/BIZR.cpp index ec4fb87a4..d80762b33 100644 --- a/src/simulation/elements/BIZR.cpp +++ b/src/simulation/elements/BIZR.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_BIZR_update(UPDATE_FUNC_ARGS); -int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS); +#include "BIZR.h" void Element::Element_BIZR() { diff --git a/src/simulation/elements/BIZR.h b/src/simulation/elements/BIZR.h new file mode 100644 index 000000000..db81a715e --- /dev/null +++ b/src/simulation/elements/BIZR.h @@ -0,0 +1,5 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS); +int Element_BIZR_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/BIZRG.cpp b/src/simulation/elements/BIZRG.cpp index 012772f92..1e30d52e0 100644 --- a/src/simulation/elements/BIZRG.cpp +++ b/src/simulation/elements/BIZRG.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_BIZR_update(UPDATE_FUNC_ARGS); -int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS); +#include "BIZR.h" void Element::Element_BIZRG() { diff --git a/src/simulation/elements/BIZRS.cpp b/src/simulation/elements/BIZRS.cpp index a8d890991..50be68c24 100644 --- a/src/simulation/elements/BIZRS.cpp +++ b/src/simulation/elements/BIZRS.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_BIZR_update(UPDATE_FUNC_ARGS); -int Element_BIZR_graphics(GRAPHICS_FUNC_ARGS); +#include "BIZR.h" void Element::Element_BIZRS() { diff --git a/src/simulation/elements/BVBR.cpp b/src/simulation/elements/BVBR.cpp index 3a1b26686..38d04ae4d 100644 --- a/src/simulation/elements/BVBR.cpp +++ b/src/simulation/elements/BVBR.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_VIBR_update(UPDATE_FUNC_ARGS); -int Element_VIBR_graphics(GRAPHICS_FUNC_ARGS); +#include "VIBR.h" void Element::Element_BVBR() { diff --git a/src/simulation/elements/COAL.cpp b/src/simulation/elements/COAL.cpp index 6f8dafbb8..ba35673ea 100644 --- a/src/simulation/elements/COAL.cpp +++ b/src/simulation/elements/COAL.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_COAL_update(UPDATE_FUNC_ARGS); -int Element_COAL_graphics(GRAPHICS_FUNC_ARGS); +#include "COAL.h" void Element::Element_COAL() { diff --git a/src/simulation/elements/COAL.h b/src/simulation/elements/COAL.h new file mode 100644 index 000000000..124496585 --- /dev/null +++ b/src/simulation/elements/COAL.h @@ -0,0 +1,5 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_COAL_graphics(GRAPHICS_FUNC_ARGS); +int Element_COAL_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/CRAY.cpp b/src/simulation/elements/CRAY.cpp index 1e5f86108..197f84cff 100644 --- a/src/simulation/elements/CRAY.cpp +++ b/src/simulation/elements/CRAY.cpp @@ -1,4 +1,5 @@ #include "simulation/ElementCommon.h" +#include "FILT.h" static int update(UPDATE_FUNC_ARGS); static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS); diff --git a/src/simulation/elements/EMP.h b/src/simulation/elements/EMP.h new file mode 100644 index 000000000..d6352f49e --- /dev/null +++ b/src/simulation/elements/EMP.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +void Element_EMP_Trigger(Simulation *sim, int triggerCount); diff --git a/src/simulation/elements/ETRD.h b/src/simulation/elements/ETRD.h new file mode 100644 index 000000000..35e799fc7 --- /dev/null +++ b/src/simulation/elements/ETRD.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId); diff --git a/src/simulation/elements/FIGH.cpp b/src/simulation/elements/FIGH.cpp index 6d32775d1..9f23603e8 100644 --- a/src/simulation/elements/FIGH.cpp +++ b/src/simulation/elements/FIGH.cpp @@ -1,15 +1,10 @@ #include "simulation/ElementCommon.h" +#include "STKM.h" static int update(UPDATE_FUNC_ARGS); static bool createAllowed(ELEMENT_CREATE_ALLOWED_FUNC_ARGS); static void changeType(ELEMENT_CHANGETYPE_FUNC_ARGS); static void Free(Simulation *sim, unsigned char i); -bool Element_FIGH_CanAlloc(Simulation *sim); -int Element_FIGH_Alloc(Simulation *sim); -void Element_FIGH_NewFighter(Simulation *sim, int fighterID, int i, int elem); -int Element_STKM_graphics(GRAPHICS_FUNC_ARGS); -void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i); -int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS); void Element::Element_FIGH() { diff --git a/src/simulation/elements/FILT.cpp b/src/simulation/elements/FILT.cpp index c78e23b33..f471a40ff 100644 --- a/src/simulation/elements/FILT.cpp +++ b/src/simulation/elements/FILT.cpp @@ -1,8 +1,8 @@ #include "simulation/ElementCommon.h" +#include "FILT.h" static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); -int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); void Element::Element_FILT() { diff --git a/src/simulation/elements/FILT.h b/src/simulation/elements/FILT.h new file mode 100644 index 000000000..9289e9218 --- /dev/null +++ b/src/simulation/elements/FILT.h @@ -0,0 +1,5 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_FILT_getWavelengths(const Particle* cpart); +int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); diff --git a/src/simulation/elements/FIRE.cpp b/src/simulation/elements/FIRE.cpp index 7e0f3ffb4..35b5b3372 100644 --- a/src/simulation/elements/FIRE.cpp +++ b/src/simulation/elements/FIRE.cpp @@ -1,7 +1,7 @@ #include "simulation/ElementCommon.h" +#include "FIRE.h" #include -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int updateLegacy(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); diff --git a/src/simulation/elements/FIRE.h b/src/simulation/elements/FIRE.h new file mode 100644 index 000000000..0d07ea535 --- /dev/null +++ b/src/simulation/elements/FIRE.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_FIRE_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/LAVA.cpp b/src/simulation/elements/LAVA.cpp index 0dcd4c3b5..c1c1f68e3 100644 --- a/src/simulation/elements/LAVA.cpp +++ b/src/simulation/elements/LAVA.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "FIRE.h" -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); diff --git a/src/simulation/elements/LDTC.cpp b/src/simulation/elements/LDTC.cpp index 2307159a1..db52e2511 100644 --- a/src/simulation/elements/LDTC.cpp +++ b/src/simulation/elements/LDTC.cpp @@ -1,5 +1,5 @@ #include "simulation/ElementCommon.h" -#include +#include "FILT.h" static int update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/LOLZ.h b/src/simulation/elements/LOLZ.h new file mode 100644 index 000000000..1eaecdab7 --- /dev/null +++ b/src/simulation/elements/LOLZ.h @@ -0,0 +1,7 @@ +#pragma once +#include "simulation/ElementDefs.h" + +extern int Element_LOLZ_RuleTable[9][9]; +extern int Element_LOLZ_lolz[XRES/9][YRES/9]; +extern int Element_LOVE_RuleTable[9][9]; +extern int Element_LOVE_love[XRES/9][YRES/9]; diff --git a/src/simulation/elements/NEUT.cpp b/src/simulation/elements/NEUT.cpp index bfd0c146a..1feb16ea4 100644 --- a/src/simulation/elements/NEUT.cpp +++ b/src/simulation/elements/NEUT.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "FIRE.h" -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); diff --git a/src/simulation/elements/NTCT.cpp b/src/simulation/elements/NTCT.cpp index 47c219eb7..3e51cd974 100644 --- a/src/simulation/elements/NTCT.cpp +++ b/src/simulation/elements/NTCT.cpp @@ -1,6 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_NTCT_update(UPDATE_FUNC_ARGS); +#include "NTCT.h" void Element::Element_NTCT() { diff --git a/src/simulation/elements/NTCT.h b/src/simulation/elements/NTCT.h new file mode 100644 index 000000000..0ceed8a5f --- /dev/null +++ b/src/simulation/elements/NTCT.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_NTCT_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/PBCN.cpp b/src/simulation/elements/PBCN.cpp index d749c0531..21ad6930e 100644 --- a/src/simulation/elements/PBCN.cpp +++ b/src/simulation/elements/PBCN.cpp @@ -1,8 +1,8 @@ #include "simulation/ElementCommon.h" +#include "PCLN.h" static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); -bool Element_PCLN_ctypeDraw(CTYPEDRAW_FUNC_ARGS); void Element::Element_PBCN() { diff --git a/src/simulation/elements/PCLN.cpp b/src/simulation/elements/PCLN.cpp index ffe0c0744..c058379b7 100644 --- a/src/simulation/elements/PCLN.cpp +++ b/src/simulation/elements/PCLN.cpp @@ -1,8 +1,8 @@ #include "simulation/ElementCommon.h" +#include "PCLN.h" static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); -bool Element_PCLN_ctypeDraw(CTYPEDRAW_FUNC_ARGS); void Element::Element_PCLN() { diff --git a/src/simulation/elements/PCLN.h b/src/simulation/elements/PCLN.h new file mode 100644 index 000000000..0d526446f --- /dev/null +++ b/src/simulation/elements/PCLN.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +bool Element_PCLN_ctypeDraw(CTYPEDRAW_FUNC_ARGS); diff --git a/src/simulation/elements/PHOT.cpp b/src/simulation/elements/PHOT.cpp index fc7b21641..d0c13cb78 100644 --- a/src/simulation/elements/PHOT.cpp +++ b/src/simulation/elements/PHOT.cpp @@ -1,6 +1,7 @@ #include "simulation/ElementCommon.h" +#include "FIRE.h" +#include "FILT.h" -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); @@ -151,7 +152,6 @@ static void create(ELEMENT_CREATE_FUNC_ARGS) float a = sim->rng.between(0, 7) * 0.78540f; sim->parts[i].vx = 3.0f * cosf(a); sim->parts[i].vy = 3.0f * sinf(a); - int Element_FILT_interactWavelengths(Simulation *sim, Particle* cpart, int origWl); if (TYP(sim->pmap[y][x]) == PT_FILT) sim->parts[i].ctype = Element_FILT_interactWavelengths(sim, &sim->parts[ID(sim->pmap[y][x])], sim->parts[i].ctype); } diff --git a/src/simulation/elements/PIPE.cpp b/src/simulation/elements/PIPE.cpp index 51ef0d410..827ef1a8d 100644 --- a/src/simulation/elements/PIPE.cpp +++ b/src/simulation/elements/PIPE.cpp @@ -1,15 +1,11 @@ #include "simulation/ElementCommon.h" +#include "PIPE.h" +#include "SOAP.h" -extern const std::array, 8> Element_PIPE_offsets; -void Element_PIPE_transformPatchOffsets(Particle &part, const std::array &offsetMap); -int Element_PIPE_update(UPDATE_FUNC_ARGS); -int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS); static void props_pipe_to_part(const Particle *pipe, Particle *part, bool STOR); -void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); static void transfer_part_to_pipe(Particle *part, Particle *pipe); static void transfer_pipe_to_pipe(Particle *src, Particle *dest, bool STOR); static void pushParticle(Simulation * sim, int i, int count, int original); -void Element_SOAP_detach(Simulation * sim, int i); void Element::Element_PIPE() { diff --git a/src/simulation/elements/PIPE.h b/src/simulation/elements/PIPE.h new file mode 100644 index 000000000..759c13675 --- /dev/null +++ b/src/simulation/elements/PIPE.h @@ -0,0 +1,11 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS); +void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); +void Element_PIPE_transformPatchOffsets(Particle &part, const std::array &offsetMap); +int Element_PIPE_update(UPDATE_FUNC_ARGS); +void Element_PPIP_flood_trigger(Simulation * sim, int x, int y, int sparkedBy); + +extern int Element_PPIP_ppip_changed; +extern const std::array, 8> Element_PIPE_offsets; diff --git a/src/simulation/elements/PLSM.cpp b/src/simulation/elements/PLSM.cpp index b737a8a0a..525442175 100644 --- a/src/simulation/elements/PLSM.cpp +++ b/src/simulation/elements/PLSM.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "FIRE.h" -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); diff --git a/src/simulation/elements/PPIP.cpp b/src/simulation/elements/PPIP.cpp index e245dbbc7..1909fd6cb 100644 --- a/src/simulation/elements/PPIP.cpp +++ b/src/simulation/elements/PPIP.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_PIPE_update(UPDATE_FUNC_ARGS); -int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS); +#include "PIPE.h" void Element::Element_PPIP() { diff --git a/src/simulation/elements/PQRT.cpp b/src/simulation/elements/PQRT.cpp index 7a2cfc8db..ef3f8e106 100644 --- a/src/simulation/elements/PQRT.cpp +++ b/src/simulation/elements/PQRT.cpp @@ -1,7 +1,6 @@ #include "simulation/ElementCommon.h" +#include "QRTZ.h" -int Element_QRTZ_update(UPDATE_FUNC_ARGS); -int Element_QRTZ_graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); void Element::Element_PQRT() diff --git a/src/simulation/elements/PRTI.cpp b/src/simulation/elements/PRTI.cpp index b41a26e8a..fb8f80261 100644 --- a/src/simulation/elements/PRTI.cpp +++ b/src/simulation/elements/PRTI.cpp @@ -1,10 +1,10 @@ #include "simulation/ElementCommon.h" #include "simulation/orbitalparts.h" +#include "PIPE.h" +#include "SOAP.h" -void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); -void Element_SOAP_detach(Simulation * sim, int i); void Element::Element_PRTI() { diff --git a/src/simulation/elements/QRTZ.cpp b/src/simulation/elements/QRTZ.cpp index 76f778eae..a0c4987b6 100644 --- a/src/simulation/elements/QRTZ.cpp +++ b/src/simulation/elements/QRTZ.cpp @@ -1,7 +1,6 @@ #include "simulation/ElementCommon.h" +#include "QRTZ.h" -int Element_QRTZ_update(UPDATE_FUNC_ARGS); -int Element_QRTZ_graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); void Element::Element_QRTZ() diff --git a/src/simulation/elements/QRTZ.h b/src/simulation/elements/QRTZ.h new file mode 100644 index 000000000..f08613b0b --- /dev/null +++ b/src/simulation/elements/QRTZ.h @@ -0,0 +1,5 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_QRTZ_graphics(GRAPHICS_FUNC_ARGS); +int Element_QRTZ_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/RFGL.cpp b/src/simulation/elements/RFGL.cpp index ee8372368..16536c204 100644 --- a/src/simulation/elements/RFGL.cpp +++ b/src/simulation/elements/RFGL.cpp @@ -1,6 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_RFRG_update(UPDATE_FUNC_ARGS); +#include "RFRG.h" void Element::Element_RFGL() { diff --git a/src/simulation/elements/RFRG.cpp b/src/simulation/elements/RFRG.cpp index 0c728ef16..50936fbff 100644 --- a/src/simulation/elements/RFRG.cpp +++ b/src/simulation/elements/RFRG.cpp @@ -1,6 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_RFRG_update(UPDATE_FUNC_ARGS); +#include "RFRG.h" void Element::Element_RFRG() { diff --git a/src/simulation/elements/RFRG.h b/src/simulation/elements/RFRG.h new file mode 100644 index 000000000..828394ef6 --- /dev/null +++ b/src/simulation/elements/RFRG.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_RFRG_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/SOAP.h b/src/simulation/elements/SOAP.h new file mode 100644 index 000000000..5c04f8b07 --- /dev/null +++ b/src/simulation/elements/SOAP.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +void Element_SOAP_detach(Simulation * sim, int i); diff --git a/src/simulation/elements/SPRK.cpp b/src/simulation/elements/SPRK.cpp index 3d2381422..bd75919ab 100644 --- a/src/simulation/elements/SPRK.cpp +++ b/src/simulation/elements/SPRK.cpp @@ -1,6 +1,9 @@ #include "simulation/ElementCommon.h" +#include "NTCT.h" +#include "PIPE.h" +#include "FIRE.h" +#include "ETRD.h" -int Element_FIRE_update(UPDATE_FUNC_ARGS); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); @@ -83,13 +86,11 @@ static int update(UPDATE_FUNC_ARGS) return 1; case PT_NTCT: case PT_PTCT: - int Element_NTCT_update(UPDATE_FUNC_ARGS); Element_NTCT_update(UPDATE_FUNC_SUBCALL_ARGS); break; case PT_ETRD: if (parts[i].life==1) { - int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId); auto nearp = Element_ETRD_nearestSparkablePart(sim, i); if (nearp!=-1 && sim->parts_avg(i, nearp, PT_INSL)!=PT_INSL) { @@ -247,7 +248,6 @@ static int update(UPDATE_FUNC_ARGS) case PT_PPIP: if (parts[i].life == 3 && pavg!=PT_INSL) { - void Element_PPIP_flood_trigger(Simulation * sim, int x, int y, int sparkedBy); if (sender == PT_NSCN || sender == PT_PSCN || sender == PT_INST) Element_PPIP_flood_trigger(sim, x+rx, y+ry, sender); } diff --git a/src/simulation/elements/STKM.cpp b/src/simulation/elements/STKM.cpp index 79f79a786..5452c1591 100644 --- a/src/simulation/elements/STKM.cpp +++ b/src/simulation/elements/STKM.cpp @@ -1,14 +1,10 @@ #include "simulation/ElementCommon.h" +#include "STKM.h" static int update(UPDATE_FUNC_ARGS); -int Element_STKM_graphics(GRAPHICS_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); static bool createAllowed(ELEMENT_CREATE_ALLOWED_FUNC_ARGS); static void changeType(ELEMENT_CHANGETYPE_FUNC_ARGS); -void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i); -int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS); -void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element); -void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int y); void Element::Element_STKM() { diff --git a/src/simulation/elements/STKM.h b/src/simulation/elements/STKM.h new file mode 100644 index 000000000..69651309b --- /dev/null +++ b/src/simulation/elements/STKM.h @@ -0,0 +1,12 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_FIGH_Alloc(Simulation *sim); +bool Element_FIGH_CanAlloc(Simulation *sim); +void Element_FIGH_NewFighter(Simulation *sim, int fighterID, int i, int elem); +int Element_STKM_graphics(GRAPHICS_FUNC_ARGS); +void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i); +void Element_STKM_interact(Simulation *sim, playerst *playerp, int i, int x, int y); +int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS); +void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element); +void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element); diff --git a/src/simulation/elements/STKM2.cpp b/src/simulation/elements/STKM2.cpp index 2ee01e931..a399ca366 100644 --- a/src/simulation/elements/STKM2.cpp +++ b/src/simulation/elements/STKM2.cpp @@ -1,12 +1,10 @@ #include "simulation/ElementCommon.h" +#include "STKM.h" static int update(UPDATE_FUNC_ARGS); static void create(ELEMENT_CREATE_FUNC_ARGS); static bool createAllowed(ELEMENT_CREATE_ALLOWED_FUNC_ARGS); static void changeType(ELEMENT_CHANGETYPE_FUNC_ARGS); -int Element_STKM_graphics(GRAPHICS_FUNC_ARGS); -void Element_STKM_init_legs(Simulation * sim, playerst *playerp, int i); -int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS); void Element::Element_STKM2() { diff --git a/src/simulation/elements/STOR.cpp b/src/simulation/elements/STOR.cpp index b2b09b475..3e93a661c 100644 --- a/src/simulation/elements/STOR.cpp +++ b/src/simulation/elements/STOR.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "SOAP.h" -void Element_SOAP_detach(Simulation * sim, int i); static int update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); static bool ctypeDraw(CTYPEDRAW_FUNC_ARGS); diff --git a/src/simulation/elements/VIBR.cpp b/src/simulation/elements/VIBR.cpp index c4005da1b..26959596c 100644 --- a/src/simulation/elements/VIBR.cpp +++ b/src/simulation/elements/VIBR.cpp @@ -1,7 +1,5 @@ #include "simulation/ElementCommon.h" - -int Element_VIBR_update(UPDATE_FUNC_ARGS); -int Element_VIBR_graphics(GRAPHICS_FUNC_ARGS); +#include "VIBR.h" void Element::Element_VIBR() { diff --git a/src/simulation/elements/VIBR.h b/src/simulation/elements/VIBR.h new file mode 100644 index 000000000..452e27784 --- /dev/null +++ b/src/simulation/elements/VIBR.h @@ -0,0 +1,5 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_VIBR_graphics(GRAPHICS_FUNC_ARGS); +int Element_VIBR_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/VIRS.cpp b/src/simulation/elements/VIRS.cpp index bd185d225..3940b77bd 100644 --- a/src/simulation/elements/VIRS.cpp +++ b/src/simulation/elements/VIRS.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "VIRS.h" -int Element_VIRS_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); void Element::Element_VIRS() diff --git a/src/simulation/elements/VIRS.h b/src/simulation/elements/VIRS.h new file mode 100644 index 000000000..a5a664dcf --- /dev/null +++ b/src/simulation/elements/VIRS.h @@ -0,0 +1,4 @@ +#pragma once +#include "simulation/ElementDefs.h" + +int Element_VIRS_update(UPDATE_FUNC_ARGS); diff --git a/src/simulation/elements/VRSG.cpp b/src/simulation/elements/VRSG.cpp index 11a204af2..bfa13aa4e 100644 --- a/src/simulation/elements/VRSG.cpp +++ b/src/simulation/elements/VRSG.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "VIRS.h" -int Element_VIRS_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); void Element::Element_VRSG() diff --git a/src/simulation/elements/VRSS.cpp b/src/simulation/elements/VRSS.cpp index 6ba0fee9f..221508393 100644 --- a/src/simulation/elements/VRSS.cpp +++ b/src/simulation/elements/VRSS.cpp @@ -1,6 +1,6 @@ #include "simulation/ElementCommon.h" +#include "VIRS.h" -int Element_VIRS_update(UPDATE_FUNC_ARGS); static int graphics(GRAPHICS_FUNC_ARGS); void Element::Element_VRSS() From 2d7b40b9e5022d1d41929f6e954aaa17bd7faa83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 14:36:07 +0100 Subject: [PATCH 08/12] Prevent Lua callbacks from being called from secondary SaveRenderers SaveRenderers populate their own Simulation with Simulation::Load, which may call various callbacks now that these SaveRenderers know about custom elements. Make sure these callbacks don't try to call into the main thread's Lua state. Seeing as these callbacks now need to be protected from races too, the scopes of some of the exclusive locks of the graphics property mutex needed to be extended. --- src/lua/LuaScriptInterface.cpp | 97 ++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 8cc3a1bdb..36f7d10bf 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -3287,6 +3287,8 @@ void LuaScriptInterface::LuaSetParticleProperty(lua_State* l, int particleID, St int LuaScriptInterface::elements_loadDefault(lua_State * l) { auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; auto &builtinElements = GetElements(); auto *luacon_ci = static_cast(commandInterface); { @@ -3304,14 +3306,10 @@ int LuaScriptInterface::elements_loadDefault(lua_State * l) lua_pushnil(l); lua_settable(l, -3); - { - std::unique_lock lk(sd.elementGraphicsMx); - auto &elements = sd.elements; - if (id < (int)builtinElements.size()) - elements[id] = builtinElements[id]; - else - elements[id] = Element(); - } + if (id < (int)builtinElements.size()) + elements[id] = builtinElements[id]; + else + elements[id] = Element(); tpt_lua_pushByteString(l, identifier); lua_pushinteger(l, id); @@ -3320,17 +3318,14 @@ int LuaScriptInterface::elements_loadDefault(lua_State * l) } else { + for (int i = 0; i < PT_NUM; i++) { - std::unique_lock lk(sd.elementGraphicsMx); - auto &elements = sd.elements; - for (int i = 0; i < PT_NUM; i++) - { - if (i < (int)builtinElements.size()) - elements[i] = builtinElements[i]; - else - elements[i] = Element(); - } + if (i < (int)builtinElements.size()) + elements[i] = builtinElements[i]; + else + elements[i] = Element(); } + lua_pushnil(l); lua_setglobal(l, "elements"); lua_pushnil(l); @@ -3446,6 +3441,10 @@ int LuaScriptInterface::elements_allocate(lua_State * l) static int luaUpdateWrapper(UPDATE_FUNC_ARGS) { + if (!sim->useLuaCallbacks) + { + return 0; + } auto *luacon_ci = static_cast(commandInterface); auto &builtinElements = GetElements(); auto *builtinUpdate = builtinElements[parts[i].type].Update; @@ -3552,6 +3551,10 @@ static int luaGraphicsWrapper(GRAPHICS_FUNC_ARGS) static void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS) { + if (!sim->useLuaCallbacks) + { + return; + } auto *luacon_ci = static_cast(commandInterface); if (luaCreateHandlers[sim->parts[i].type]) { @@ -3571,6 +3574,13 @@ static void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS) static bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS) { + if (!sim->useLuaCallbacks) + { + // Nothing really bad can happen, no callbacks are allowed anyway. The worst thing that can happen + // is that a well-crafted save looks odd in previews because it has multiple Element::defaultGraphics-rendered + // instances of something that should be limited to one instance. + return 1; + } auto *luacon_ci = static_cast(commandInterface); bool ret = false; if (luaCreateAllowedHandlers[t]) @@ -3597,6 +3607,10 @@ static bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS) static void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS) { + if (!sim->useLuaCallbacks) + { + return; + } auto *luacon_ci = static_cast(commandInterface); if (luaChangeTypeHandlers[sim->parts[i].type]) { @@ -3616,6 +3630,10 @@ static void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS) static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS) { + if (!sim->useLuaCallbacks) + { + return false; + } auto *luacon_ci = static_cast(commandInterface); bool ret = false; if (luaCtypeDrawHandlers[sim->parts[i].type]) @@ -3651,8 +3669,8 @@ int LuaScriptInterface::elements_element(lua_State * l) if (lua_gettop(l) > 1) { - auto &sd = SimulationData::Ref(); { + auto &sd = SimulationData::Ref(); std::unique_lock lk(sd.elementGraphicsMx); auto &elements = sd.elements; luaL_checktype(l, 2, LUA_TTABLE); @@ -3748,15 +3766,15 @@ int LuaScriptInterface::elements_element(lua_State * l) elements[id].CtypeDraw = builtinElements[id].CtypeDraw; } lua_pop(l, 1); + + lua_getfield(l, -1, "DefaultProperties"); + SetDefaultProperties(l, id, lua_gettop(l)); + lua_pop(l, 1); + + sd.graphicscache[id].isready = 0; } - - lua_getfield(l, -1, "DefaultProperties"); - SetDefaultProperties(l, id, lua_gettop(l)); - lua_pop(l, 1); - luacon_model->BuildMenus(); luacon_ci->custom_init_can_move(); - sd.graphicscache[id].isready = 0; return 0; } @@ -3855,9 +3873,11 @@ int LuaScriptInterface::elements_property(lua_State * l) if (lua_gettop(l) > 2) { + auto &sd = SimulationData::Ref(); + std::unique_lock lk(sd.elementGraphicsMx); + auto &elements = sd.elements; if (prop != properties.end()) { - auto &sd = SimulationData::Ref(); if (lua_type(l, 3) != LUA_TNIL) { if (prop->Type == StructProperty::TransitionType) @@ -3868,22 +3888,15 @@ int LuaScriptInterface::elements_property(lua_State * l) return luaL_error(l, "Invalid element"); } } - { - std::unique_lock lk(sd.elementGraphicsMx); - auto &elements = sd.elements; - intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset); - LuaSetProperty(l, *prop, propertyAddress, 3); - } + intptr_t propertyAddress = (intptr_t)(((unsigned char*)&elements[id]) + prop->Offset); + LuaSetProperty(l, *prop, propertyAddress, 3); + luacon_model->BuildMenus(); + luacon_ci->custom_init_can_move(); + sd.graphicscache[id].isready = 0; } - - luacon_model->BuildMenus(); - luacon_ci->custom_init_can_move(); - sd.graphicscache[id].isready = 0; } else if (propertyName == "Update") { - auto &sd = SimulationData::Ref(); - auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { switch (luaL_optint(l, 4, 0)) @@ -3912,8 +3925,6 @@ int LuaScriptInterface::elements_property(lua_State * l) } else if (propertyName == "Graphics") { - auto &sd = SimulationData::Ref(); - auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { lua_gr_func[id].Assign(l, 3); @@ -3928,8 +3939,6 @@ int LuaScriptInterface::elements_property(lua_State * l) } else if (propertyName == "Create") { - auto &sd = SimulationData::Ref(); - auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaCreateHandlers[id].Assign(l, 3); @@ -3943,8 +3952,6 @@ int LuaScriptInterface::elements_property(lua_State * l) } else if (propertyName == "CreateAllowed") { - auto &sd = SimulationData::Ref(); - auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaCreateAllowedHandlers[id].Assign(l, 3); @@ -3958,8 +3965,6 @@ int LuaScriptInterface::elements_property(lua_State * l) } else if (propertyName == "ChangeType") { - auto &sd = SimulationData::Ref(); - auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaChangeTypeHandlers[id].Assign(l, 3); @@ -3973,8 +3978,6 @@ int LuaScriptInterface::elements_property(lua_State * l) } else if (propertyName == "CtypeDraw") { - auto &sd = SimulationData::Ref(); - auto &elements = sd.elements; if (lua_type(l, 3) == LUA_TFUNCTION) { luaCtypeDrawHandlers[id].Assign(l, 3); From cc27126f27aa6593387bd315b780657e4b1b27c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 15:35:26 +0100 Subject: [PATCH 09/12] Move palette code to GameSave Because Simulation shouldn't need to know about palettes. --- src/client/GameSave.cpp | 101 ++++++++++++++++++++++++++- src/client/GameSave.h | 5 ++ src/client/ThumbnailRendererTask.cpp | 2 +- src/gui/game/GameView.cpp | 2 +- src/gui/preview/PreviewView.cpp | 4 +- src/simulation/SaveRenderer.cpp | 6 +- src/simulation/SaveRenderer.h | 3 +- src/simulation/Simulation.cpp | 85 +--------------------- src/simulation/Simulation.h | 3 +- 9 files changed, 115 insertions(+), 96 deletions(-) diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index f506a0485..2baead119 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -47,6 +47,83 @@ GameSave::GameSave(const std::vector &data, bool newWantAuthors) } } +void GameSave::MapPalette() +{ + int partMap[PT_NUM]; + for(int i = 0; i < PT_NUM; i++) + { + partMap[i] = i; + } + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if(palette.size()) + { + for(int i = 0; i < PT_NUM; i++) + { + partMap[i] = 0; + } + for(auto &pi : palette) + { + if (pi.second > 0 && pi.second < PT_NUM) + { + int myId = 0; + for (int i = 0; i < PT_NUM; i++) + { + if (elements[i].Enabled && elements[i].Identifier == pi.first) + { + myId = i; + } + } + if (myId) + { + partMap[pi.second] = myId; + } + else + { + missingElements.identifiers.insert(pi); + } + } + } + } + auto paletteLookup = [this, &partMap](int type) { + if (type > 0 && type < PT_NUM) + { + auto carriedType = partMap[type]; + if (!carriedType) // type is not 0 so this shouldn't be 0 either + { + missingElements.ids.insert(type); + } + type = carriedType; + } + return type; + }; + + unsigned int pmapmask = (1<= PT_NUM) + { + continue; + } + tempPart.type = paletteLookup(tempPart.type); + for (auto index : possiblyCarriesType) + { + if (elements[tempPart.type].CarriesTypeIn & (1U << index)) + { + auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); + auto carriedType = *prop & int(pmapmask); + auto extra = *prop >> pmapbits; + carriedType = paletteLookup(carriedType); + *prop = PMAP(extra, carriedType); + } + } + } +} + void GameSave::Expand(const std::vector &data) { try @@ -68,6 +145,7 @@ void GameSave::Expand(const std::vector &data) std::cerr << "Got Magic number '" << data[0] << data[1] << data[2] << "'" << std::endl; throw ParseException(ParseException::Corrupt, "Invalid save format"); } + MapPalette(); } else { @@ -1980,6 +2058,9 @@ std::pair> GameSave::serialiseOPS() const std::vector partsSaveIndex(NPART); unsigned int partsCount = 0; std::fill(&partsSaveIndex[0], &partsSaveIndex[0] + NPART, 0); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + std::set paletteSet; for (auto pos : partS.OriginRect().Range()) { //Find the first particle in this position @@ -1997,6 +2078,16 @@ std::pair> GameSave::serialiseOPS() const //Store saved particle index+1 for this partsptr index (0 means not saved) partsSaveIndex[i] = (partsCount++) + 1; + paletteSet.insert(particles[i].type); + for (auto index : possiblyCarriesType) + { + if (elements[particles[i].type].CarriesTypeIn & (1U << index)) + { + auto *prop = reinterpret_cast(reinterpret_cast(&particles[i]) + properties[index].Offset); + paletteSet.insert(TYP(*prop)); + } + } + //Type (required) partsData[partsDataLen++] = particles[i].type; @@ -2250,6 +2341,12 @@ std::pair> GameSave::serialiseOPS() const } } + std::vector paletteData; + for (int ID : paletteSet) + { + paletteData.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID)); + } + unsigned int soapLinkDataLen = 0; std::vector soapLinkData(3*soapCount); if (soapCount) @@ -2381,10 +2478,10 @@ std::pair> GameSave::serialiseOPS() const { bson_append_binary(&b, "parts", (char)BSON_BIN_USER, (const char *)&partsData[0], partsDataLen); - if (palette.size()) + if (paletteData.size()) { bson_append_start_array(&b, "palette"); - for(auto iter = palette.begin(), end = palette.end(); iter != end; ++iter) + for(auto iter = paletteData.begin(), end = paletteData.end(); iter != end; ++iter) { bson_append_int(&b, (*iter).first.c_str(), (*iter).second); } diff --git a/src/client/GameSave.h b/src/client/GameSave.h index a22d359a3..bf34a6563 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -5,6 +5,7 @@ #include "common/Version.h" #include "simulation/Sign.h" #include "simulation/Particle.h" +#include "simulation/MissingElements.h" #include "Misc.h" #include "SimulationConfig.h" #include @@ -62,6 +63,8 @@ class GameSave void readPSv(const std::vector &data); std::pair> serialiseOPS() const; + void MapPalette(); + public: Vec2 blockSize = { 0, 0 }; bool fromNewerVersion = false; @@ -101,6 +104,8 @@ public: int edgeMode = 0; bool wantAuthors = true; + MissingElements missingElements; + //Signs std::vector signs; StkmData stkm; diff --git a/src/client/ThumbnailRendererTask.cpp b/src/client/ThumbnailRendererTask.cpp index 5267ed88d..fe40d5802 100644 --- a/src/client/ThumbnailRendererTask.cpp +++ b/src/client/ThumbnailRendererTask.cpp @@ -29,7 +29,7 @@ ThumbnailRendererTask::~ThumbnailRendererTask() bool ThumbnailRendererTask::doWork() { - std::tie(thumbnail, std::ignore) = SaveRenderer::Ref().Render(save.get(), decorations, fire); + thumbnail = SaveRenderer::Ref().Render(save.get(), decorations, fire); if (thumbnail) { thumbnail->ResizeToFit(size, true); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 9599efc92..d1379cc90 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -1964,7 +1964,7 @@ void GameView::NotifyTransformedPlaceSaveChanged(GameModel *sender) { if (sender->GetTransformedPlaceSave()) { - std::tie(placeSaveThumb, std::ignore) = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer()); + placeSaveThumb = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer()); selectMode = PlaceSave; selectPoint2 = mousePosition; } diff --git a/src/gui/preview/PreviewView.cpp b/src/gui/preview/PreviewView.cpp index 05506539a..5c322d05d 100644 --- a/src/gui/preview/PreviewView.cpp +++ b/src/gui/preview/PreviewView.cpp @@ -4,6 +4,7 @@ #include "client/Client.h" #include "client/SaveInfo.h" +#include "client/GameSave.h" #include "client/http/AddCommentRequest.h" #include "client/http/ReportSaveRequest.h" @@ -570,7 +571,8 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender) if(save->GetGameSave()) { - std::tie(savePreview, missingElements) = SaveRenderer::Ref().Render(save->GetGameSave(), false, true); + missingElements = save->GetGameSave()->missingElements; + savePreview = SaveRenderer::Ref().Render(save->GetGameSave(), false, true); if (savePreview) savePreview->ResizeToFit(RES / 2, true); missingElementsButton->Visible = missingElements.identifiers.size() || missingElements.ids.size(); diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index 3f938d2b8..733409f76 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -18,7 +18,7 @@ SaveRenderer::SaveRenderer() SaveRenderer::~SaveRenderer() = default; -std::pair, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) +std::unique_ptr SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) { // this function usually runs on a thread different from where element info in SimulationData may be written, so we acquire a read-only lock on it auto &sd = SimulationData::CRef(); @@ -35,7 +35,7 @@ std::pair, MissingElements> SaveRenderer::Render(co sim->clear_sim(); - auto missingElementTypes = sim->Load(save, true, { 0, 0 }); + sim->Load(save, true, { 0, 0 }); ren->decorations_enable = true; ren->blackDecorations = !decorations; ren->ClearAccumulation(); @@ -59,5 +59,5 @@ std::pair, MissingElements> SaveRenderer::Render(co auto tempThumb = std::make_unique(save->blockSize * CELL); tempThumb->BlendImage(ren->Data(), 0xFF, ren->Size().OriginRect()); - return { std::move(tempThumb), missingElementTypes }; + return tempThumb; } diff --git a/src/simulation/SaveRenderer.h b/src/simulation/SaveRenderer.h index dc913e1d9..a5fffca98 100644 --- a/src/simulation/SaveRenderer.h +++ b/src/simulation/SaveRenderer.h @@ -5,7 +5,6 @@ #include #include "common/ExplicitSingleton.h" #include "common/String.h" -#include "MissingElements.h" class GameSave; class VideoBuffer; @@ -21,5 +20,5 @@ class SaveRenderer: public ExplicitSingleton public: SaveRenderer(); ~SaveRenderer(); - std::pair, MissingElements> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); + std::unique_ptr Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); }; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index a48b45527..b1040f7d9 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -22,67 +22,15 @@ static float remainder_p(float x, float y) return std::fmod(x, y) + (x>=0 ? 0 : y); } -MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates +void Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates { - MissingElements missingElements; auto partP = blockP * CELL; - unsigned int pmapmask = (1<pmapbits)-1; - - int partMap[PT_NUM]; - for(int i = 0; i < PT_NUM; i++) - { - partMap[i] = i; - } auto &sd = SimulationData::CRef(); auto &elements = sd.elements; - if(save->palette.size()) - { - for(int i = 0; i < PT_NUM; i++) - { - partMap[i] = 0; - } - for(auto &pi : save->palette) - { - if (pi.second > 0 && pi.second < PT_NUM) - { - int myId = 0; - for (int i = 0; i < PT_NUM; i++) - { - if (elements[i].Enabled && elements[i].Identifier == pi.first) - { - myId = i; - } - } - if (myId) - { - partMap[pi.second] = myId; - } - else - { - missingElements.identifiers.insert(pi); - } - } - } - } - auto paletteLookup = [&partMap, &missingElements](int type) { - if (type > 0 && type < PT_NUM) - { - auto carriedType = partMap[type]; - if (!carriedType) // type is not 0 so this shouldn't be 0 either - { - missingElements.ids.insert(type); - } - type = carriedType; - } - return type; - }; RecalcFreeParticles(false); - auto &possiblyCarriesType = Particle::PossiblyCarriesType(); - auto &properties = Particle::GetProperties(); - std::map soapList; for (int n = 0; n < NPART && n < save->particlesCount; n++) { @@ -97,26 +45,12 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec int x = int(tempPart.x + 0.5f); int y = int(tempPart.y + 0.5f); - // Check various scenarios where we are unable to spawn the element, and set type to 0 to block spawning later if (!InBounds(x, y)) { continue; } - tempPart.type = paletteLookup(tempPart.type); - for (auto index : possiblyCarriesType) - { - if (elements[tempPart.type].CarriesTypeIn & (1U << index)) - { - auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); - auto carriedType = *prop & int(pmapmask); - auto extra = *prop >> save->pmapbits; - carriedType = paletteLookup(carriedType); - *prop = PMAP(extra, carriedType); - } - } - // Ensure we can spawn this element if ((player.spwn == 1 && tempPart.type==PT_STKM) || (player2.spwn == 1 && tempPart.type==PT_STKM2)) { @@ -339,8 +273,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec { air->ApproximateBlockAirMaps(); } - - return missingElements; } std::unique_ptr Simulation::Save(bool includePressure, Rect partR) // particle coordinates @@ -349,8 +281,6 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR auto blockP = blockR.TopLeft; auto newSave = std::make_unique(blockR.Size()); - auto &possiblyCarriesType = Particle::PossiblyCarriesType(); - auto &properties = Particle::GetProperties(); newSave->frameCount = frameCount; newSave->rngState = rng.state(); @@ -360,7 +290,6 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR // Map of soap particles loaded into this save, old ID -> new ID // Now stores all particles, not just SOAP (but still only used for soap) std::map particleMap; - std::set paletteSet; auto &sd = SimulationData::CRef(); auto &elements = sd.elements; @@ -381,22 +310,10 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR storedParts++; elementCount[tempPart.type]++; - paletteSet.insert(tempPart.type); - for (auto index : possiblyCarriesType) - { - if (elements[tempPart.type].CarriesTypeIn & (1U << index)) - { - auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); - paletteSet.insert(TYP(*prop)); - } - } } } } - for (int ID : paletteSet) - newSave->palette.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID)); - if (storedParts && elementCount[PT_SOAP]) { // fix SOAP links using particleMap, a map of old particle ID -> new particle ID diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 21f0fc82c..c23a80d4f 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -11,7 +11,6 @@ #include "common/tpt-rand.h" #include "Element.h" #include "SimulationConfig.h" -#include "MissingElements.h" #include #include #include @@ -114,7 +113,7 @@ public: uint64_t frameCount; bool ensureDeterminism; - MissingElements Load(const GameSave *save, bool includePressure, Vec2 blockP); // block coordinates + void Load(const GameSave *save, bool includePressure, Vec2 blockP); // block coordinates std::unique_ptr Save(bool includePressure, Rect partR); // particle coordinates void SaveSimOptions(GameSave &gameSave); SimulationSample GetSample(int x, int y); From 28b5b6dc97a30653dadff68176b55a54e9967dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 16:51:42 +0100 Subject: [PATCH 10/12] Fix some LTO-related emscripten link-time error I have absolutely no idea. The error in question is the following: wasm-ld: error: /home/lbphacker/.emscripten_cache/sysroot/lib/wasm32-emscripten/lto/libhtml5.a(callback.o): attempt to add bitcode file after LTO (_emscripten_run_callback_on_thread) I have no idea where we use _emscripten_run_callback_on_thread, and I have no idea why LTO would think it's not required when it's obviously required. This commit fixes it by holding the linker's hand even more than it already had. --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 7d78d3237..db7963020 100644 --- a/meson.build +++ b/meson.build @@ -212,6 +212,7 @@ if host_platform == 'emscripten' '-s', 'FS_DEBUG', '-s', 'MODULARIZE', '-s', 'EXPORT_NAME=create_' + app_exe, + '-Wl,-u,_emscripten_run_callback_on_thread', '-lidbfs.js', ] emcc_args = [ From 7ab52f8becbbf82d34b0494358d08bd5bddc5876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 20:04:15 +0100 Subject: [PATCH 11/12] Snapshot 354 --- meson_options.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index 44a15d4cb..34b3a7904 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -54,7 +54,7 @@ option( 'build_num', type: 'integer', min: 0, - value: 353, + value: 354, description: 'Build number, should be strictly monotonously increasing across public releases' ) option( @@ -75,7 +75,7 @@ option( 'upstream_build_num', type: 'integer', min: 0, - value: 353, + value: 354, description: 'Upstream build number, mod owners should not change this but merge upstream changes to it' ) option( From a38e1c48bbf029257700af957e14787a7d34d03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sun, 10 Dec 2023 13:38:33 +0100 Subject: [PATCH 12/12] Default to identity mapping elements not in the palette for pre-98.0 saves Newer saves include an element palette which maps save-space element numbers to element identifier strings, see 29189693b381. This is useful because the numbers of custom elements can change, while their identifiers are expected to not change. Not all elements make it into the palette, only the ones that are in use in the save. 98.0 is staged to extend this feature in two ways. First, it'll warn the user of missing custom elements when loading a save that uses such elements, see 36800a76cd97. Second, it'll do a better job of deciding what to put in the element palette, see a13c29875f64. In order for detection of missing elements to work, a save's palette has to account for every element number used in the save, including built-in elements. To dispel a misunderstanding regarding that last part: yes, including built-in elements is not crucial if the set of built-in elements only ever grows, but this is not guaranteed. 98.0 creates such palettes, but older code didn't, for various reasons. One reason is that the palette at some point wasn't meant to include built-in elements, see e0d982367b71, although this was rectified later in 67b87b1dab9f. Another reason is that not all cases of element numbers encoded in particle properties were considered, see for example f45d0d1683ed and 1f1062408c98. Palettes in existing saves being thus incomplete didn't use to be a problem because older code would just assume that whatever element number wasn't listed in the palette referred to a built-in element and would just map such save-space element numbers to the same simulation-space element number, hence identity mapping. However, this approach doesn't cover custom elements whose numbers can change, nor does it cover extra built-in elements added by a mod. Worse, a different mod with different extra built-in elements may map save-space element numbers not listed in the palette to its own extra elements. As a solution to these problems and making use of the fact that palettes are now complete and comprehensive, 98.0 no longer does this default identity mapping, see 73be29aa6113. Removing this identity mapping in itself would have broken older saves that use the old identifiers of some elements; that commit works around that by remapping these early in the loading process. By the way, these changes in identifiers are perfect examples of the set of built-in elements changing in ways other than growing. This still doesn't address the problem in the case of pre-98.0 saves though. Such saves have seemingly valid element numbers (although it's impossible to tell whether these refer to built-in elements from vanilla or extra built-in elements from a mod) but no corresponding entry in their palettes. The user is warned about such elements also, see 9f8449357f73. Lacking a better solution, this commit assumes that these elements are indeed vanilla elements and re-enables the default identity mapping for such saves. In summary, this commit fixes the loading process for saves that were made in 97.0 or some older version and use built-in vanilla elements in ways that didn't trigger their inclusion in the element palette. For example, until a13c29875f64, CONV's tmp was not considered by the palette code, so any CONV with tmp set to an element that wasn't a built-in vanilla element, and which also wasn't used anywhere else in the save, would have been potentially corrupted by the loading process. An example a save that demonstrates this behaviour is id:2633868, which has CRAY particles on the right with ctype set to LIGH, but until this commit, these ctypes would have been set to 0 and the user would have been warned about element number 87 (LIGH) missing from the palette. --- src/client/GameSave.cpp | 7 +++++-- src/common/Version.h | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 2baead119..75050f46c 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -59,9 +59,12 @@ void GameSave::MapPalette() auto &elements = sd.elements; if(palette.size()) { - for(int i = 0; i < PT_NUM; i++) + if (version >= Version(98, 0)) { - partMap[i] = 0; + for(int i = 0; i < PT_NUM; i++) + { + partMap[i] = 0; + } } for(auto &pi : palette) { diff --git a/src/common/Version.h b/src/common/Version.h index ae215e3f0..c8febaad7 100644 --- a/src/common/Version.h +++ b/src/common/Version.h @@ -27,6 +27,21 @@ struct Version return *this < other || *this == other; } + constexpr bool operator >=(const Version &other) const + { + return !(*this < other); + } + + constexpr bool operator >(const Version &other) const + { + return !(*this <= other); + } + + constexpr bool operator !=(const Version &other) const + { + return !(*this == other); + } + constexpr size_t operator [](size_t index) const { return components[index];