Move palette code to GameSave
Because Simulation shouldn't need to know about palettes.
This commit is contained in:
parent
2d7b40b9e5
commit
cc27126f27
@ -47,6 +47,83 @@ GameSave::GameSave(const std::vector<char> &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<<pmapbits)-1;
|
||||
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
|
||||
auto &properties = Particle::GetProperties();
|
||||
for (int n = 0; n < NPART && n < particlesCount; n++)
|
||||
{
|
||||
Particle &tempPart = particles[n];
|
||||
if (tempPart.type <= 0 || tempPart.type >= PT_NUM)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
tempPart.type = paletteLookup(tempPart.type);
|
||||
for (auto index : possiblyCarriesType)
|
||||
{
|
||||
if (elements[tempPart.type].CarriesTypeIn & (1U << index))
|
||||
{
|
||||
auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&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<char> &data)
|
||||
{
|
||||
try
|
||||
@ -68,6 +145,7 @@ void GameSave::Expand(const std::vector<char> &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<bool, std::vector<char>> GameSave::serialiseOPS() const
|
||||
std::vector<unsigned> partsSaveIndex(NPART);
|
||||
unsigned int partsCount = 0;
|
||||
std::fill(&partsSaveIndex[0], &partsSaveIndex[0] + NPART, 0);
|
||||
auto &sd = SimulationData::CRef();
|
||||
auto &elements = sd.elements;
|
||||
std::set<int> paletteSet;
|
||||
for (auto pos : partS.OriginRect().Range<TOP_TO_BOTTOM, LEFT_TO_RIGHT>())
|
||||
{
|
||||
//Find the first particle in this position
|
||||
@ -1997,6 +2078,16 @@ std::pair<bool, std::vector<char>> 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<const int *>(reinterpret_cast<const char *>(&particles[i]) + properties[index].Offset);
|
||||
paletteSet.insert(TYP(*prop));
|
||||
}
|
||||
}
|
||||
|
||||
//Type (required)
|
||||
partsData[partsDataLen++] = particles[i].type;
|
||||
|
||||
@ -2250,6 +2341,12 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PaletteItem> paletteData;
|
||||
for (int ID : paletteSet)
|
||||
{
|
||||
paletteData.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID));
|
||||
}
|
||||
|
||||
unsigned int soapLinkDataLen = 0;
|
||||
std::vector<unsigned char> soapLinkData(3*soapCount);
|
||||
if (soapCount)
|
||||
@ -2381,10 +2478,10 @@ std::pair<bool, std::vector<char>> 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);
|
||||
}
|
||||
|
@ -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 <vector>
|
||||
@ -62,6 +63,8 @@ class GameSave
|
||||
void readPSv(const std::vector<char> &data);
|
||||
std::pair<bool, std::vector<char>> serialiseOPS() const;
|
||||
|
||||
void MapPalette();
|
||||
|
||||
public:
|
||||
Vec2<int> blockSize = { 0, 0 };
|
||||
bool fromNewerVersion = false;
|
||||
@ -101,6 +104,8 @@ public:
|
||||
int edgeMode = 0;
|
||||
bool wantAuthors = true;
|
||||
|
||||
MissingElements missingElements;
|
||||
|
||||
//Signs
|
||||
std::vector<sign> signs;
|
||||
StkmData stkm;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -18,7 +18,7 @@ SaveRenderer::SaveRenderer()
|
||||
|
||||
SaveRenderer::~SaveRenderer() = default;
|
||||
|
||||
std::pair<std::unique_ptr<VideoBuffer>, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource)
|
||||
std::unique_ptr<VideoBuffer> 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<std::unique_ptr<VideoBuffer>, 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<std::unique_ptr<VideoBuffer>, MissingElements> SaveRenderer::Render(co
|
||||
auto tempThumb = std::make_unique<VideoBuffer>(save->blockSize * CELL);
|
||||
tempThumb->BlendImage(ren->Data(), 0xFF, ren->Size().OriginRect());
|
||||
|
||||
return { std::move(tempThumb), missingElementTypes };
|
||||
return tempThumb;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <vector>
|
||||
#include "common/ExplicitSingleton.h"
|
||||
#include "common/String.h"
|
||||
#include "MissingElements.h"
|
||||
|
||||
class GameSave;
|
||||
class VideoBuffer;
|
||||
@ -21,5 +20,5 @@ class SaveRenderer: public ExplicitSingleton<SaveRenderer>
|
||||
public:
|
||||
SaveRenderer();
|
||||
~SaveRenderer();
|
||||
std::pair<std::unique_ptr<VideoBuffer>, MissingElements> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr);
|
||||
std::unique_ptr<VideoBuffer> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr);
|
||||
};
|
||||
|
@ -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<int> blockP) // block coordinates
|
||||
void Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> blockP) // block coordinates
|
||||
{
|
||||
MissingElements missingElements;
|
||||
auto partP = blockP * CELL;
|
||||
unsigned int pmapmask = (1<<save->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<unsigned int, unsigned int> 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<int *>(reinterpret_cast<char *>(&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<GameSave> Simulation::Save(bool includePressure, Rect<int> partR) // particle coordinates
|
||||
@ -349,8 +281,6 @@ std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> partR
|
||||
auto blockP = blockR.TopLeft;
|
||||
|
||||
auto newSave = std::make_unique<GameSave>(blockR.Size());
|
||||
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
|
||||
auto &properties = Particle::GetProperties();
|
||||
newSave->frameCount = frameCount;
|
||||
newSave->rngState = rng.state();
|
||||
|
||||
@ -360,7 +290,6 @@ std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> 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<unsigned int, unsigned int> particleMap;
|
||||
std::set<int> paletteSet;
|
||||
|
||||
auto &sd = SimulationData::CRef();
|
||||
auto &elements = sd.elements;
|
||||
@ -381,22 +310,10 @@ std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> partR
|
||||
storedParts++;
|
||||
elementCount[tempPart.type]++;
|
||||
|
||||
paletteSet.insert(tempPart.type);
|
||||
for (auto index : possiblyCarriesType)
|
||||
{
|
||||
if (elements[tempPart.type].CarriesTypeIn & (1U << index))
|
||||
{
|
||||
auto *prop = reinterpret_cast<const int *>(reinterpret_cast<const char *>(&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
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "common/tpt-rand.h"
|
||||
#include "Element.h"
|
||||
#include "SimulationConfig.h"
|
||||
#include "MissingElements.h"
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
@ -114,7 +113,7 @@ public:
|
||||
uint64_t frameCount;
|
||||
bool ensureDeterminism;
|
||||
|
||||
MissingElements Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates
|
||||
void Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates
|
||||
std::unique_ptr<GameSave> Save(bool includePressure, Rect<int> partR); // particle coordinates
|
||||
void SaveSimOptions(GameSave &gameSave);
|
||||
SimulationSample GetSample(int x, int y);
|
||||
|
Reference in New Issue
Block a user