Merge branch 'merryweather' into 'master'

Replace more sized reads and change weather loading

See merge request OpenMW/openmw!3496
macos_ci_fix
psi29a 1 year ago
commit 9259f5c056

@ -1201,16 +1201,10 @@ namespace EsmTool
std::cout << " Name: " << mData.mName << std::endl; std::cout << " Name: " << mData.mName << std::endl;
std::cout << " Weather:" << std::endl; std::cout << " Weather:" << std::endl;
std::cout << " Clear: " << (int)mData.mData.mClear << std::endl; std::array<std::string_view, 10> weathers
std::cout << " Cloudy: " << (int)mData.mData.mCloudy << std::endl; = { "Clear", "Cloudy", "Fog", "Overcast", "Rain", "Thunder", "Ash", "Blight", "Snow", "Blizzard" };
std::cout << " Foggy: " << (int)mData.mData.mFoggy << std::endl; for (size_t i = 0; i < weathers.size(); ++i)
std::cout << " Overcast: " << (int)mData.mData.mOvercast << std::endl; std::cout << " " << weathers[i] << ": " << mData.mData.mProbabilities[i] << std::endl;
std::cout << " Rain: " << (int)mData.mData.mOvercast << std::endl;
std::cout << " Thunder: " << (int)mData.mData.mThunder << std::endl;
std::cout << " Ash: " << (int)mData.mData.mAsh << std::endl;
std::cout << " Blight: " << (int)mData.mData.mBlight << std::endl;
std::cout << " Snow: " << (int)mData.mData.mSnow << std::endl;
std::cout << " Blizzard: " << (int)mData.mData.mBlizzard << std::endl;
std::cout << " Map Color: " << mData.mMapColor << std::endl; std::cout << " Map Color: " << mData.mMapColor << std::endl;
if (!mData.mSleepList.empty()) if (!mData.mSleepList.empty())
std::cout << " Sleep List: " << mData.mSleepList << std::endl; std::cout << " Sleep List: " << mData.mSleepList << std::endl;

@ -47,9 +47,7 @@ void CSMTools::RegionCheckStage::perform(int stage, CSMDoc::Messages& messages)
/// \todo test that the ID in mSleeplist exists /// \todo test that the ID in mSleeplist exists
// test that chances add up to 100 // test that chances add up to 100
int chances = region.mData.mClear + region.mData.mCloudy + region.mData.mFoggy + region.mData.mOvercast auto chances = std::accumulate(region.mData.mProbabilities.begin(), region.mData.mProbabilities.end(), 0u);
+ region.mData.mRain + region.mData.mThunder + region.mData.mAsh + region.mData.mBlight + region.mData.mSnow
+ region.mData.mBlizzard;
if (chances != 100) if (chances != 100)
messages.add(id, "Weather chances do not add up to 100", "", CSMDoc::Message::Severity_Error); messages.add(id, "Weather chances do not add up to 100", "", CSMDoc::Message::Severity_Error);

@ -1076,31 +1076,8 @@ namespace CSMWorld
} }
else if (subColIndex == 1) else if (subColIndex == 1)
{ {
switch (subRowIndex) if (subRowIndex >= 0 && static_cast<size_t>(subRowIndex) < region.mData.mProbabilities.size())
{ return region.mData.mProbabilities[subRowIndex];
case 0:
return region.mData.mClear;
case 1:
return region.mData.mCloudy;
case 2:
return region.mData.mFoggy;
case 3:
return region.mData.mOvercast;
case 4:
return region.mData.mRain;
case 5:
return region.mData.mThunder;
case 6:
return region.mData.mAsh;
case 7:
return region.mData.mBlight;
case 8:
return region.mData.mSnow;
case 9:
return region.mData.mBlizzard;
default:
break;
}
} }
throw std::runtime_error("index out of range"); throw std::runtime_error("index out of range");
@ -1110,45 +1087,11 @@ namespace CSMWorld
Record<ESM::Region>& record, const QVariant& value, int subRowIndex, int subColIndex) const Record<ESM::Region>& record, const QVariant& value, int subRowIndex, int subColIndex) const
{ {
ESM::Region region = record.get(); ESM::Region region = record.get();
unsigned char chance = static_cast<unsigned char>(value.toInt()); uint8_t chance = static_cast<uint8_t>(value.toInt());
if (subColIndex == 1) if (subColIndex == 1)
{ {
switch (subRowIndex) region.mData.mProbabilities.at(subRowIndex) = chance;
{
case 0:
region.mData.mClear = chance;
break;
case 1:
region.mData.mCloudy = chance;
break;
case 2:
region.mData.mFoggy = chance;
break;
case 3:
region.mData.mOvercast = chance;
break;
case 4:
region.mData.mRain = chance;
break;
case 5:
region.mData.mThunder = chance;
break;
case 6:
region.mData.mAsh = chance;
break;
case 7:
region.mData.mBlight = chance;
break;
case 8:
region.mData.mSnow = chance;
break;
case 9:
region.mData.mBlizzard = chance;
break;
default:
throw std::runtime_error("index out of range");
}
record.setModified(region); record.setModified(region);
} }

@ -232,7 +232,7 @@ namespace MWBase
virtual void setMoonColour(bool red) = 0; virtual void setMoonColour(bool red) = 0;
virtual void modRegion(const ESM::RefId& regionid, const std::vector<char>& chances) = 0; virtual void modRegion(const ESM::RefId& regionid, const std::vector<uint8_t>& chances) = 0;
virtual void changeToInteriorCell( virtual void changeToInteriorCell(
std::string_view cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) std::string_view cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true)

@ -102,11 +102,11 @@ namespace MWScript
std::string_view region{ runtime.getStringLiteral(runtime[0].mInteger) }; std::string_view region{ runtime.getStringLiteral(runtime[0].mInteger) };
runtime.pop(); runtime.pop();
std::vector<char> chances; std::vector<uint8_t> chances;
chances.reserve(10); chances.reserve(10);
while (arg0 > 0) while (arg0 > 0)
{ {
chances.push_back(std::clamp(runtime[0].mInteger, 0, 127)); chances.push_back(std::clamp(runtime[0].mInteger, 0, 100));
runtime.pop(); runtime.pop();
arg0--; arg0--;
} }

@ -285,19 +285,8 @@ namespace MWWorld
RegionWeather::RegionWeather(const ESM::Region& region) RegionWeather::RegionWeather(const ESM::Region& region)
: mWeather(invalidWeatherID) : mWeather(invalidWeatherID)
, mChances() , mChances(region.mData.mProbabilities.begin(), region.mData.mProbabilities.end())
{ {
mChances.reserve(10);
mChances.push_back(region.mData.mClear);
mChances.push_back(region.mData.mCloudy);
mChances.push_back(region.mData.mFoggy);
mChances.push_back(region.mData.mOvercast);
mChances.push_back(region.mData.mRain);
mChances.push_back(region.mData.mThunder);
mChances.push_back(region.mData.mAsh);
mChances.push_back(region.mData.mBlight);
mChances.push_back(region.mData.mSnow);
mChances.push_back(region.mData.mBlizzard);
} }
RegionWeather::RegionWeather(const ESM::RegionWeatherState& state) RegionWeather::RegionWeather(const ESM::RegionWeatherState& state)
@ -313,19 +302,9 @@ namespace MWWorld
return state; return state;
} }
void RegionWeather::setChances(const std::vector<char>& chances) void RegionWeather::setChances(const std::vector<uint8_t>& chances)
{ {
if (mChances.size() < chances.size()) mChances = chances;
{
mChances.reserve(chances.size());
}
int i = 0;
for (char chance : chances)
{
mChances[i] = chance;
i++;
}
// Regional weather no longer supports the current type, select a new weather pattern. // Regional weather no longer supports the current type, select a new weather pattern.
if ((static_cast<size_t>(mWeather) >= mChances.size()) || (mChances[mWeather] == 0)) if ((static_cast<size_t>(mWeather) >= mChances.size()) || (mChances[mWeather] == 0))
@ -357,15 +336,14 @@ namespace MWWorld
// If chances A and B has values 30 and 70 then by generating 100 numbers 1..100, 30% will be lesser or equal 30 // If chances A and B has values 30 and 70 then by generating 100 numbers 1..100, 30% will be lesser or equal 30
// and 70% will be greater than 30 (in theory). // and 70% will be greater than 30 (in theory).
auto& prng = MWBase::Environment::get().getWorld()->getPrng(); auto& prng = MWBase::Environment::get().getWorld()->getPrng();
int chance = Misc::Rng::rollDice(100, prng) + 1; // 1..100 unsigned int chance = static_cast<unsigned int>(Misc::Rng::rollDice(100, prng) + 1); // 1..100
int sum = 0; unsigned int sum = 0;
int i = 0; for (size_t i = 0; i < mChances.size(); ++i)
for (; static_cast<size_t>(i) < mChances.size(); ++i)
{ {
sum += mChances[i]; sum += mChances[i];
if (chance <= sum) if (chance <= sum)
{ {
mWeather = i; mWeather = static_cast<int>(i);
return; return;
} }
} }
@ -649,7 +627,7 @@ namespace MWWorld
} }
} }
void WeatherManager::modRegion(const ESM::RefId& regionID, const std::vector<char>& chances) void WeatherManager::modRegion(const ESM::RefId& regionID, const std::vector<uint8_t>& chances)
{ {
// Sets the region's probability for various weather patterns. Note that this appears to be saved permanently. // Sets the region's probability for various weather patterns. Note that this appears to be saved permanently.
// In Morrowind, this seems to have the following behavior when applied to the current region: // In Morrowind, this seems to have the following behavior when applied to the current region:

@ -230,7 +230,7 @@ namespace MWWorld
operator ESM::RegionWeatherState() const; operator ESM::RegionWeatherState() const;
void setChances(const std::vector<char>& chances); void setChances(const std::vector<uint8_t>& chances);
void setWeather(int weatherID); void setWeather(int weatherID);
@ -238,7 +238,7 @@ namespace MWWorld
private: private:
int mWeather; int mWeather;
std::vector<char> mChances; std::vector<uint8_t> mChances;
void chooseNewWeather(); void chooseNewWeather();
}; };
@ -286,7 +286,7 @@ namespace MWWorld
* @param ID of the weather setting to shift to * @param ID of the weather setting to shift to
*/ */
void changeWeather(const ESM::RefId& regionID, const unsigned int weatherID); void changeWeather(const ESM::RefId& regionID, const unsigned int weatherID);
void modRegion(const ESM::RefId& regionID, const std::vector<char>& chances); void modRegion(const ESM::RefId& regionID, const std::vector<uint8_t>& chances);
void playerTeleported(const ESM::RefId& playerRegion, bool isExterior); void playerTeleported(const ESM::RefId& playerRegion, bool isExterior);
/** /**

@ -1879,7 +1879,7 @@ namespace MWWorld
mWeatherManager->changeWeather(region, id); mWeatherManager->changeWeather(region, id);
} }
void World::modRegion(const ESM::RefId& regionid, const std::vector<char>& chances) void World::modRegion(const ESM::RefId& regionid, const std::vector<uint8_t>& chances)
{ {
mWeatherManager->modRegion(regionid, chances); mWeatherManager->modRegion(regionid, chances);
} }

@ -329,7 +329,7 @@ namespace MWWorld
void setMoonColour(bool red) override; void setMoonColour(bool red) override;
void modRegion(const ESM::RefId& regionid, const std::vector<char>& chances) override; void modRegion(const ESM::RefId& regionid, const std::vector<uint8_t>& chances) override;
void changeToInteriorCell(const std::string_view cellName, const ESM::Position& position, bool adjustPlayerPos, void changeToInteriorCell(const std::string_view cellName, const ESM::Position& position, bool adjustPlayerPos,
bool changeEvent = true) override; bool changeEvent = true) override;

@ -27,15 +27,14 @@ namespace ESM
{ {
esm.getSubHeader(); esm.getSubHeader();
// Cold weather not included before 1.3 // Cold weather not included before 1.3
if (esm.getSubSize() == sizeof(mData)) if (esm.getSubSize() == mData.mProbabilities.size())
{ {
esm.getTSized<10>(mData); esm.getT(mData.mProbabilities);
} }
else if (esm.getSubSize() == sizeof(mData) - 2) else if (esm.getSubSize() == mData.mProbabilities.size() - 2)
{ {
mData.mSnow = 0; mData.mProbabilities.fill(0);
mData.mBlizzard = 0; esm.getExact(&mData.mProbabilities, esm.getSubSize());
esm.getExact(&mData, sizeof(mData) - 2);
} }
else else
{ {
@ -85,9 +84,9 @@ namespace ESM
esm.writeHNOCString("FNAM", mName); esm.writeHNOCString("FNAM", mName);
if (esm.getVersion() == VER_12) if (esm.getVersion() == VER_12)
esm.writeHNT("WEAT", mData, sizeof(mData) - 2); esm.writeHNT("WEAT", mData.mProbabilities, mData.mProbabilities.size() - 2);
else else
esm.writeHNT("WEAT", mData); esm.writeHNT("WEAT", mData.mProbabilities);
esm.writeHNOCRefId("BNAM", mSleepList); esm.writeHNOCRefId("BNAM", mSleepList);
@ -104,8 +103,7 @@ namespace ESM
void Region::blank() void Region::blank()
{ {
mRecordFlags = 0; mRecordFlags = 0;
mData.mClear = mData.mCloudy = mData.mFoggy = mData.mOvercast = mData.mRain = mData.mThunder = mData.mAsh mData.mProbabilities.fill(0);
= mData.mBlight = mData.mSnow = mData.mBlizzard = 0;
mMapColor = 0; mMapColor = 0;

@ -1,6 +1,7 @@
#ifndef OPENMW_ESM_REGN_H #ifndef OPENMW_ESM_REGN_H
#define OPENMW_ESM_REGN_H #define OPENMW_ESM_REGN_H
#include <array>
#include <string> #include <string>
#include <vector> #include <vector>
@ -24,26 +25,24 @@ namespace ESM
/// Return a string descriptor for this record type. Currently used for debugging / error logs only. /// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string_view getRecordType() { return "Region"; } static std::string_view getRecordType() { return "Region"; }
#pragma pack(push)
#pragma pack(1)
struct WEATstruct struct WEATstruct
{ {
// These are probabilities that add up to 100 // These are probabilities that add up to 100
unsigned char mClear, mCloudy, mFoggy, mOvercast, mRain, mThunder, mAsh, mBlight, mSnow, mBlizzard; // Clear, Cloudy, Foggy, Overcast, Rain, Thunder, Ash, Blight, Snow, Blizzard
std::array<uint8_t, 10> mProbabilities;
}; // 10 bytes }; // 10 bytes
#pragma pack(pop)
// Reference to a sound that is played randomly in this region // Reference to a sound that is played randomly in this region
struct SoundRef struct SoundRef
{ {
ESM::RefId mSound; ESM::RefId mSound;
unsigned char mChance; uint8_t mChance;
}; };
WEATstruct mData; WEATstruct mData;
int mMapColor; // RGBA int32_t mMapColor; // RGBA
unsigned int mRecordFlags; uint32_t mRecordFlags;
// sleepList refers to a leveled list of creatures you can meet if // sleepList refers to a leveled list of creatures you can meet if
// you sleep outside in this region. // you sleep outside in this region.
RefId mId, mSleepList; RefId mId, mSleepList;

@ -28,7 +28,7 @@ namespace ESM
mName = esm.getHString(); mName = esm.getHString();
break; break;
case fourCC("RIDT"): case fourCC("RIDT"):
esm.getHTSized<16>(mData); esm.getHT(mData.mWeight, mData.mValue, mData.mUses, mData.mQuality);
hasData = true; hasData = true;
break; break;
case fourCC("SCRI"): case fourCC("SCRI"):

@ -22,14 +22,14 @@ namespace ESM
struct Data struct Data
{ {
float mWeight; float mWeight;
int mValue; int32_t mValue;
int mUses; int32_t mUses;
float mQuality; float mQuality;
}; // Size = 16 }; // Size = 16
Data mData; Data mData;
unsigned int mRecordFlags; uint32_t mRecordFlags;
RefId mId, mScript; RefId mId, mScript;
std::string mName, mModel, mIcon; std::string mName, mModel, mIcon;

@ -12,12 +12,12 @@ namespace ESM
{ {
void Script::loadSCVR(ESMReader& esm) void Script::loadSCVR(ESMReader& esm)
{ {
int s = mData.mStringTableSize; uint32_t s = mData.mStringTableSize;
std::vector<char> tmp(s); std::vector<char> tmp(s);
// not using getHExact, vanilla doesn't seem to mind unused bytes at the end // not using getHExact, vanilla doesn't seem to mind unused bytes at the end
esm.getSubHeader(); esm.getSubHeader();
int left = esm.getSubSize(); uint32_t left = esm.getSubSize();
if (left < s) if (left < s)
esm.fail("SCVR string list is smaller than specified"); esm.fail("SCVR string list is smaller than specified");
esm.getExact(tmp.data(), s); esm.getExact(tmp.data(), s);
@ -99,7 +99,11 @@ namespace ESM
{ {
esm.getSubHeader(); esm.getSubHeader();
mId = esm.getMaybeFixedRefIdSize(32); mId = esm.getMaybeFixedRefIdSize(32);
esm.getTSized<20>(mData); esm.getT(mData.mNumShorts);
esm.getT(mData.mNumLongs);
esm.getT(mData.mNumFloats);
esm.getT(mData.mScriptDataSize);
esm.getT(mData.mStringTableSize);
hasHeader = true; hasHeader = true;
break; break;
@ -114,7 +118,7 @@ namespace ESM
esm.getSubHeader(); esm.getSubHeader();
uint32_t subSize = esm.getSubSize(); uint32_t subSize = esm.getSubSize();
if (subSize != static_cast<uint32_t>(mData.mScriptDataSize)) if (subSize != mData.mScriptDataSize)
{ {
std::stringstream ss; std::stringstream ss;
ss << "Script data size defined in SCHD subrecord does not match size of SCDT subrecord"; ss << "Script data size defined in SCHD subrecord does not match size of SCDT subrecord";

@ -29,7 +29,7 @@ namespace ESM
{ {
/// Data from script-precompling in the editor. /// Data from script-precompling in the editor.
/// \warning Do not use them. OpenCS currently does not precompile scripts. /// \warning Do not use them. OpenCS currently does not precompile scripts.
int mNumShorts, mNumLongs, mNumFloats, mScriptDataSize, mStringTableSize; uint32_t mNumShorts, mNumLongs, mNumFloats, mScriptDataSize, mStringTableSize;
}; };
struct SCHD struct SCHD
{ {
@ -37,7 +37,7 @@ namespace ESM
Script::SCHDstruct mData; Script::SCHDstruct mData;
}; };
unsigned int mRecordFlags; uint32_t mRecordFlags;
RefId mId; RefId mId;
SCHDstruct mData; SCHDstruct mData;

@ -55,7 +55,7 @@ namespace ESM
hasIndex = true; hasIndex = true;
break; break;
case fourCC("SKDT"): case fourCC("SKDT"):
esm.getHTSized<24>(mData); esm.getHT(mData.mAttribute, mData.mSpecialization, mData.mUseValue);
hasData = true; hasData = true;
break; break;
case fourCC("DESC"): case fourCC("DESC"):

@ -24,7 +24,7 @@ namespace ESM
ESM::RefId mFailureSound; ESM::RefId mFailureSound;
ESM::RefId mHitSound; ESM::RefId mHitSound;
std::string mName; std::string mName;
int mAutoCalcMax; int32_t mAutoCalcMax;
static constexpr int Length = 6; static constexpr int Length = 6;
@ -44,13 +44,13 @@ namespace ESM
/// Return a string descriptor for this record type. Currently used for debugging / error logs only. /// Return a string descriptor for this record type. Currently used for debugging / error logs only.
static std::string_view getRecordType() { return "Skill"; } static std::string_view getRecordType() { return "Skill"; }
unsigned int mRecordFlags; uint32_t mRecordFlags;
SkillId mId; SkillId mId;
struct SKDTstruct struct SKDTstruct
{ {
int mAttribute; // see defs.hpp int32_t mAttribute; // see defs.hpp
int mSpecialization; // 0 - Combat, 1 - Magic, 2 - Stealth int32_t mSpecialization; // 0 - Combat, 1 - Magic, 2 - Stealth
float mUseValue[4]; // How much skill improves through use. Meaning float mUseValue[4]; // How much skill improves through use. Meaning
// of each field depends on what skill this // of each field depends on what skill this
// is. We should document this better later. // is. We should document this better later.

@ -29,7 +29,8 @@ namespace ESM
mName = esm.getHString(); mName = esm.getHString();
break; break;
case fourCC("WPDT"): case fourCC("WPDT"):
esm.getHTSized<32>(mData); esm.getHT(mData.mWeight, mData.mValue, mData.mType, mData.mHealth, mData.mSpeed, mData.mReach,
mData.mEnchant, mData.mChop, mData.mSlash, mData.mThrust, mData.mFlags);
hasData = true; hasData = true;
break; break;
case fourCC("SCRI"): case fourCC("SCRI"):

@ -62,19 +62,19 @@ namespace ESM
struct WPDTstruct struct WPDTstruct
{ {
float mWeight; float mWeight;
int mValue; int32_t mValue;
short mType; int16_t mType;
unsigned short mHealth; uint16_t mHealth;
float mSpeed, mReach; float mSpeed, mReach;
unsigned short mEnchant; // Enchantment points. The real value is mEnchant/10.f uint16_t mEnchant; // Enchantment points. The real value is mEnchant/10.f
unsigned char mChop[2], mSlash[2], mThrust[2]; // Min and max unsigned char mChop[2], mSlash[2], mThrust[2]; // Min and max
int mFlags; int32_t mFlags;
}; // 32 bytes }; // 32 bytes
#pragma pack(pop) #pragma pack(pop)
WPDTstruct mData; WPDTstruct mData;
unsigned int mRecordFlags; uint32_t mRecordFlags;
RefId mId, mEnchant, mScript; RefId mId, mEnchant, mScript;
std::string mName, mModel, mIcon; std::string mName, mModel, mIcon;

@ -41,7 +41,7 @@ namespace ESM
esm.getHNT(region.mWeather, regionWeatherRecord); esm.getHNT(region.mWeather, regionWeatherRecord);
while (esm.isNextSub(regionChanceRecord)) while (esm.isNextSub(regionChanceRecord))
{ {
char chance; uint8_t chance;
esm.getHT(chance); esm.getHT(chance);
region.mChances.push_back(chance); region.mChances.push_back(chance);
} }
@ -66,9 +66,9 @@ namespace ESM
{ {
esm.writeHNCRefId(regionNameRecord, it->first); esm.writeHNCRefId(regionNameRecord, it->first);
esm.writeHNT(regionWeatherRecord, it->second.mWeather); esm.writeHNT(regionWeatherRecord, it->second.mWeather);
for (size_t i = 0; i < it->second.mChances.size(); ++i) for (const uint8_t& chance : it->second.mChances)
{ {
esm.writeHNT(regionChanceRecord, it->second.mChances[i]); esm.writeHNT(regionChanceRecord, chance);
} }
} }
} }

@ -13,8 +13,8 @@ namespace ESM
struct RegionWeatherState struct RegionWeatherState
{ {
int mWeather; int32_t mWeather;
std::vector<char> mChances; std::vector<uint8_t> mChances;
}; };
struct WeatherState struct WeatherState
@ -24,9 +24,9 @@ namespace ESM
bool mFastForward; bool mFastForward;
float mWeatherUpdateTime; float mWeatherUpdateTime;
float mTransitionFactor; float mTransitionFactor;
int mCurrentWeather; int32_t mCurrentWeather;
int mNextWeather; int32_t mNextWeather;
int mQueuedWeather; int32_t mQueuedWeather;
std::map<ESM::RefId, RegionWeatherState> mRegions; std::map<ESM::RefId, RegionWeatherState> mRegions;
void load(ESMReader& esm); void load(ESMReader& esm);

Loading…
Cancel
Save