Don't mangle custom element types in life, ctype, tmp{,2,3,4}
Achieved by adding a new element property called CarriesTypeIn, whose bits signal to save loading code which properties of particles of the element class in question carry element IDs. The bits in this property are numbered the same way as sim.FIELD_* constants for consistency. One would signal from Lua that a custom element carries element IDs in its tmp like this: elem.property(id, "CarriesTypeIn", 2 ^ sim.FIELD_TMP) "Carrying an element ID in a property" is to be interpreted as follows: the property is treated as a combination of a PMAPBITS-bit (so, currently 9-bit) unsigned integer lower part holding an element ID and a 32-PMAPBITS-bit (so, currently 23-bit) signed integer upper part holding whatever makes sense for the element. CONV, for example, uses this signed integer in its ctype as the extra "v" parameter for particle creation.
This commit is contained in:
parent
2e2c3181b5
commit
a13c29875f
@ -1250,7 +1250,7 @@ void GameSave::readPSv(const std::vector<char> &dataVec)
|
||||
char tempSignText[255];
|
||||
sign tempSign("", 0, 0, sign::Left);
|
||||
|
||||
std::vector<Element> elements = GetElements();
|
||||
auto &elements = 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
|
||||
@ -2046,6 +2046,9 @@ std::pair<bool, std::vector<char>> 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 &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.
|
||||
// In practice, a Particle will never need as much space in the save as in memory; this is just an upper bound to simplify allocation.
|
||||
std::vector<unsigned char> partsData(NPART * (sizeof(Particle)+3));
|
||||
@ -2273,17 +2276,16 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
|
||||
}
|
||||
if (PMAPBITS > 8)
|
||||
{
|
||||
if (TypeInCtype(particles[i].type, particles[i].ctype) && particles[i].ctype > 0xFF)
|
||||
for (auto index : possiblyCarriesType)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
}
|
||||
else if (TypeInTmp(particles[i].type) && particles[i].tmp > 0xFF)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
}
|
||||
else if (TypeInTmp2(particles[i].type, particles[i].tmp2) && particles[i].tmp2 > 0xFF)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
if (elements[particles[i].type].CarriesTypeIn & (1U << index))
|
||||
{
|
||||
auto *prop = reinterpret_cast<const int *>(reinterpret_cast<const char *>(&particles[i]) + properties[index].Offset);
|
||||
if (TYP(*prop) > 0xFF)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (particles[i].type == PT_LDTC)
|
||||
@ -2684,26 +2686,6 @@ static void ConvertJsonToBson(bson *b, Json::Value j, int depth)
|
||||
}
|
||||
}
|
||||
|
||||
bool GameSave::TypeInCtype(int type, int ctype)
|
||||
{
|
||||
return ctype >= 0 && ctype < PT_NUM &&
|
||||
(type == PT_CLNE || type == PT_PCLN || type == PT_BCLN || type == PT_PBCN ||
|
||||
type == PT_STOR || type == PT_CONV || type == PT_STKM || type == PT_STKM2 ||
|
||||
type == PT_FIGH || type == PT_LAVA || type == PT_SPRK || type == PT_PSTN ||
|
||||
type == PT_CRAY || type == PT_DTEC || type == PT_DRAY || type == PT_PIPE ||
|
||||
type == PT_PPIP || type == PT_LDTC);
|
||||
}
|
||||
|
||||
bool GameSave::TypeInTmp(int type)
|
||||
{
|
||||
return type == PT_STOR;
|
||||
}
|
||||
|
||||
bool GameSave::TypeInTmp2(int type, int tmp2)
|
||||
{
|
||||
return (type == PT_VIRS || type == PT_VRSG || type == PT_VRSS) && (tmp2 >= 0 && tmp2 < PT_NUM);
|
||||
}
|
||||
|
||||
bool GameSave::PressureInTmp3(int type)
|
||||
{
|
||||
return type == PT_QRTZ || type == PT_GLAS || type == PT_TUNG;
|
||||
|
@ -141,9 +141,6 @@ public:
|
||||
|
||||
void Expand(const std::vector<char> &data);
|
||||
|
||||
static bool TypeInCtype(int type, int ctype);
|
||||
static bool TypeInTmp(int type);
|
||||
static bool TypeInTmp2(int type, int tmp2);
|
||||
static bool PressureInTmp3(int type);
|
||||
|
||||
GameSave& operator << (Particle &v);
|
||||
|
@ -35,6 +35,8 @@ void initLegacyProps()
|
||||
legacyPropNames.insert(std::pair<ByteString, StructProperty>("menu", prop));
|
||||
else if (prop.Name == "PhotonReflectWavelengths")
|
||||
continue;
|
||||
else if (prop.Name == "CarriesTypeIn")
|
||||
continue;
|
||||
else if (prop.Name == "Temperature")
|
||||
legacyPropNames.insert(std::pair<ByteString, StructProperty>("heat", prop));
|
||||
else if (prop.Name == "HeatConduct")
|
||||
|
@ -32,6 +32,7 @@ Element::Element():
|
||||
Description("No description"),
|
||||
|
||||
Properties(TYPE_SOLID),
|
||||
CarriesTypeIn(0),
|
||||
|
||||
LowPressure(IPL),
|
||||
LowPressureTransition(NT),
|
||||
@ -75,6 +76,7 @@ std::vector<StructProperty> const &Element::GetProperties()
|
||||
{ "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 ) },
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
unsigned char HeatConduct;
|
||||
String Description;
|
||||
unsigned int Properties;
|
||||
unsigned int CarriesTypeIn;
|
||||
|
||||
float LowPressure;
|
||||
int LowPressureTransition;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "Particle.h"
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
|
||||
std::vector<StructProperty> const &Particle::GetProperties()
|
||||
{
|
||||
@ -31,3 +32,31 @@ std::vector<StructPropertyAlias> const &Particle::GetPropertyAliases()
|
||||
};
|
||||
return aliases;
|
||||
}
|
||||
|
||||
std::vector<int> const &Particle::PossiblyCarriesType()
|
||||
{
|
||||
struct DoOnce
|
||||
{
|
||||
std::vector<int> indices = {
|
||||
FIELD_LIFE,
|
||||
FIELD_CTYPE,
|
||||
FIELD_TMP,
|
||||
FIELD_TMP2,
|
||||
FIELD_TMP3,
|
||||
FIELD_TMP4,
|
||||
};
|
||||
|
||||
DoOnce()
|
||||
{
|
||||
auto &properties = GetProperties();
|
||||
for (auto index : indices)
|
||||
{
|
||||
// code that depends on PossiblyCarriesType only knows how to set ints
|
||||
assert(properties[index].Type == StructProperty::Integer ||
|
||||
properties[index].Type == StructProperty::ParticleType);
|
||||
}
|
||||
}
|
||||
};
|
||||
static DoOnce doOnce;
|
||||
return doOnce.indices;
|
||||
}
|
||||
|
@ -18,4 +18,13 @@ struct Particle
|
||||
by higher-level processes referring to them by name such as Lua or the property tool **/
|
||||
static std::vector<StructProperty> const &GetProperties();
|
||||
static std::vector<StructPropertyAlias> const &GetPropertyAliases();
|
||||
static std::vector<int> const &PossiblyCarriesType();
|
||||
};
|
||||
|
||||
// important: these are indices into the vector returned by Particle::GetProperties, not indices into Particle
|
||||
constexpr unsigned int FIELD_LIFE = 1;
|
||||
constexpr unsigned int FIELD_CTYPE = 2;
|
||||
constexpr unsigned int FIELD_TMP = 9;
|
||||
constexpr unsigned int FIELD_TMP2 = 10;
|
||||
constexpr unsigned int FIELD_TMP3 = 11;
|
||||
constexpr unsigned int FIELD_TMP4 = 12;
|
||||
|
@ -65,6 +65,9 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu
|
||||
|
||||
RecalcFreeParticles(false);
|
||||
|
||||
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
|
||||
auto &properties = Particle::GetProperties();
|
||||
|
||||
bool doFullScan = false;
|
||||
for (int n = 0; n < NPART && n < save->particlesCount; n++)
|
||||
{
|
||||
@ -89,30 +92,19 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu
|
||||
continue;
|
||||
}
|
||||
type = partMap[type];
|
||||
// These store type in ctype, but are special because they store extra information in the bits after type
|
||||
if (type == PT_CRAY || type == PT_DRAY || type == PT_CONV)
|
||||
for (auto index : possiblyCarriesType)
|
||||
{
|
||||
int ctype = tempPart->ctype & pmapmask;
|
||||
int extra = tempPart->ctype >> save->pmapbits;
|
||||
if (ctype >= 0 && ctype < PT_NUM)
|
||||
ctype = partMap[ctype];
|
||||
tempPart->ctype = PMAP(extra, ctype);
|
||||
}
|
||||
else if (GameSave::TypeInCtype(type, tempPart->ctype))
|
||||
{
|
||||
tempPart->ctype = partMap[tempPart->ctype];
|
||||
}
|
||||
// also stores extra bits past type (only STOR right now)
|
||||
if (GameSave::TypeInTmp(type))
|
||||
{
|
||||
int tmp = tempPart->tmp & pmapmask;
|
||||
int extra = tempPart->tmp >> save->pmapbits;
|
||||
tmp = partMap[TYP(tmp)];
|
||||
tempPart->tmp = PMAP(extra, tmp);
|
||||
}
|
||||
if (GameSave::TypeInTmp2(type, tempPart->tmp2))
|
||||
{
|
||||
tempPart->tmp2 = partMap[tempPart->tmp2];
|
||||
if (elements[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;
|
||||
if (carriedType >= 0 && carriedType < PT_NUM)
|
||||
{
|
||||
carriedType = partMap[carriedType];
|
||||
}
|
||||
*prop = PMAP(extra, carriedType);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we can spawn this element
|
||||
@ -377,6 +369,8 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full
|
||||
blockH = blockY2-blockY;
|
||||
|
||||
GameSave * newSave = new GameSave(blockW, blockH);
|
||||
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
|
||||
auto &properties = Particle::GetProperties();
|
||||
|
||||
int storedParts = 0;
|
||||
int elementCount[PT_NUM];
|
||||
@ -403,12 +397,14 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full
|
||||
elementCount[tempPart.type]++;
|
||||
|
||||
paletteSet.insert(tempPart.type);
|
||||
if (GameSave::TypeInCtype(tempPart.type, tempPart.ctype))
|
||||
paletteSet.insert(tempPart.ctype);
|
||||
if (GameSave::TypeInTmp(tempPart.type))
|
||||
paletteSet.insert(TYP(tempPart.tmp));
|
||||
if (GameSave::TypeInTmp2(tempPart.type, tempPart.tmp2))
|
||||
paletteSet.insert(tempPart.tmp2);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ void Element::Element_BCLN()
|
||||
Description = "Breakable Clone.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_LIFE_DEC | PROP_LIFE_KILL_DEC | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,6 +32,7 @@ void Element::Element_CLNE()
|
||||
Description = "Clone. Duplicates any particles it touches.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,6 +32,7 @@ void Element::Element_CONV()
|
||||
Description = "Converter. Converts everything into whatever it first touches.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = (1U << FIELD_CTYPE) | (1U << FIELD_TMP);
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_CRAY()
|
||||
Description = "Particle Ray Emitter. Creates a beam of particles set by its ctype, with a range set by tmp.";
|
||||
|
||||
Properties = TYPE_SOLID;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,6 +32,7 @@ void Element::Element_DRAY()
|
||||
Description = "Duplicator ray. Replicates a line of particles in front of it.";
|
||||
|
||||
Properties = TYPE_SOLID;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,6 +32,7 @@ void Element::Element_DTEC()
|
||||
Description = "Detector, creates a spark when something with its ctype is nearby.";
|
||||
|
||||
Properties = TYPE_SOLID;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -43,6 +43,7 @@ void Element::Element_FIGH()
|
||||
Description = "Fighter. Tries to kill stickmen. You must first give it an element to kill him with.";
|
||||
|
||||
Properties = PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -36,6 +36,7 @@ void Element::Element_LAVA()
|
||||
Description = "Molten lava. Ignites flammable materials. Generated when metals and other materials melt, solidifies when cold.";
|
||||
|
||||
Properties = TYPE_LIQUID|PROP_LIFE_DEC;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -33,6 +33,7 @@ void Element::Element_LDTC()
|
||||
Description = "Linear detector. Scans in 8 directions for particles with its ctype and creates a spark on the opposite side.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_PBCN()
|
||||
Description = "Powered breakable clone.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_PCLN()
|
||||
Description = "Powered clone. When activated, duplicates any particles it touches.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -39,6 +39,7 @@ void Element::Element_PIPE()
|
||||
Description = "PIPE, moves particles around. Once the BRCK generates, erase some for the exit. Then the PIPE generates and is usable.";
|
||||
|
||||
Properties = TYPE_SOLID|PROP_LIFE_DEC;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_PPIP()
|
||||
Description = "Powered version of PIPE, use PSCN/NSCN to Activate/Deactivate.";
|
||||
|
||||
Properties = TYPE_SOLID|PROP_LIFE_DEC;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -39,6 +39,7 @@ void Element::Element_PSTN()
|
||||
Description = "Piston, extends and pushes particles.";
|
||||
|
||||
Properties = TYPE_SOLID;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -35,6 +35,7 @@ void Element::Element_SPRK()
|
||||
Description = "Electricity. The basis of all electronics in TPT, travels along wires and other conductive elements.";
|
||||
|
||||
Properties = TYPE_SOLID|PROP_LIFE_DEC;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -42,6 +42,7 @@ void Element::Element_STKM()
|
||||
Description = "Stickman. Don't kill him! Control with the arrow keys.";
|
||||
|
||||
Properties = PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -40,6 +40,7 @@ void Element::Element_STKM2()
|
||||
Description = "Second stickman. Don't kill him! Control with wasd.";
|
||||
|
||||
Properties = PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -35,6 +35,7 @@ void Element::Element_STOR()
|
||||
Description = "Storage. Captures and stores a single particle. Releases when charged with PSCN, also passes to PIPE.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = (1U << FIELD_CTYPE) | (1U << FIELD_TMP);
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_VIRS()
|
||||
Description = "Virus. Turns everything it touches into virus.";
|
||||
|
||||
Properties = TYPE_LIQUID|PROP_DEADLY;
|
||||
CarriesTypeIn = 1U << FIELD_TMP2;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_VRSG()
|
||||
Description = "Gas Virus. Turns everything it touches into virus.";
|
||||
|
||||
Properties = TYPE_GAS|PROP_DEADLY;
|
||||
CarriesTypeIn = 1U << FIELD_TMP2;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_VRSS()
|
||||
Description = "Solid Virus. Turns everything it touches into virus.";
|
||||
|
||||
Properties = TYPE_SOLID|PROP_DEADLY;
|
||||
CarriesTypeIn = 1U << FIELD_TMP2;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
Loading…
Reference in New Issue
Block a user