1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-25 21:38:59 +02:00

Merge pull request #5224 from IvanSavenko/misc_fixes

Fixes for 1.6.3
This commit is contained in:
Ivan Savenko 2025-01-08 22:06:57 +02:00 committed by GitHub
commit f8312737bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 108 additions and 30 deletions

View File

@ -11,7 +11,7 @@
#pragma once
#define NKAI_PATHFINDER_TRACE_LEVEL 0
constexpr int NKAI_GRAPH_TRACE_LEVEL = 0;
constexpr int NKAI_GRAPH_TRACE_LEVEL = 0; // To actually enable graph visualization, enter `/vslog graph` in game chat
#define NKAI_TRACE_LEVEL 0
#include "../../../lib/pathfinder/CGPathNode.h"

View File

@ -17,6 +17,7 @@
#include "../render/Colors.h"
#include "../render/EFont.h"
#include "../render/IFont.h"
#include "../render/IScreenHandler.h"
#include "../render/IRenderHandler.h"
#include "../render/Graphics.h"
#include "../gui/TextAlignment.h"
@ -30,24 +31,20 @@ MapOverlayLogVisualizer::MapOverlayLogVisualizer(Canvas & target, std::shared_pt
void MapOverlayLogVisualizer::drawLine(int3 start, int3 end)
{
const Point offset = Point(30, 30);
auto level = model->getLevel();
if(start.z != level || end.z != level)
return;
auto pStart = model->getTargetTileArea(start).topLeft();
auto pEnd = model->getTargetTileArea(end).topLeft();
auto viewPort = target.getRenderArea();
int scaling = GH.screenHandler().getScalingFactor();
auto pStart = model->getTargetTileArea(start).center();
auto pEnd = model->getTargetTileArea(end).center();
Rect viewPortRaw = target.getRenderArea();
Rect viewPort(viewPortRaw.topLeft() / scaling, viewPortRaw.dimensions() / scaling );
pStart.x += 3;
pEnd.x -= 3;
Point workaroundOffset(8,8); // not sure why it is needed. Removing leads to incorrect clipping near view edges
pStart += offset;
pEnd += offset;
if(viewPort.isInside(pStart) && viewPort.isInside(pEnd))
if(viewPort.isInside(pStart + workaroundOffset) && viewPort.isInside(pEnd + workaroundOffset))
{
target.drawLine(pStart, pEnd, ColorRGBA(255, 255, 0), ColorRGBA(255, 0, 0));
}

View File

@ -65,7 +65,7 @@ void BasicMapView::render(Canvas & target, bool fullUpdate)
tilesCache->update(controller->getContext());
tilesCache->render(controller->getContext(), targetClipped, fullUpdate);
MapOverlayLogVisualizer r(target, model);
MapOverlayLogVisualizer r(targetClipped, model);
logVisual->visualize(r);
}

View File

@ -59,8 +59,18 @@ static si64 lodSeek(void * opaque, si64 pos, int whence)
return data->seek(pos);
}
static void logFFmpegError(int errorCode)
{
std::array<char, AV_ERROR_MAX_STRING_SIZE> errorMessage{};
av_strerror(errorCode, errorMessage.data(), errorMessage.size());
logGlobal->warn("Failed to open video file! Reason: %s", errorMessage.data());
}
[[noreturn]] static void throwFFmpegError(int errorCode)
{
logFFmpegError(errorCode);
std::array<char, AV_ERROR_MAX_STRING_SIZE> errorMessage{};
av_strerror(errorCode, errorMessage.data(), errorMessage.size());
@ -95,7 +105,7 @@ bool FFMpegStream::openInput(const VideoPath & videoToOpen)
return input != nullptr;
}
void FFMpegStream::openContext()
bool FFMpegStream::openContext()
{
static const int BUFFER_SIZE = 4096;
input->seek(0);
@ -109,13 +119,21 @@ void FFMpegStream::openContext()
int avfopen = avformat_open_input(&formatContext, "dummyFilename", nullptr, nullptr);
if(avfopen != 0)
throwFFmpegError(avfopen);
{
logFFmpegError(avfopen);
return false;
}
// Retrieve stream information
int findStreamInfo = avformat_find_stream_info(formatContext, nullptr);
if(avfopen < 0)
throwFFmpegError(findStreamInfo);
{
logFFmpegError(findStreamInfo);
return false;
}
return true;
}
void FFMpegStream::openCodec(int desiredStreamIndex)
@ -169,10 +187,13 @@ const AVFrame * FFMpegStream::getCurrentFrame() const
return frame;
}
void CVideoInstance::openVideo()
bool CVideoInstance::openVideo()
{
openContext();
if (!openContext())
return false;
openCodec(findVideoStream());
return true;
}
void CVideoInstance::prepareOutput(float scaleFactor, bool useTextureOutput)
@ -526,7 +547,9 @@ std::pair<std::unique_ptr<ui8 []>, si64> CAudioInstance::extractAudio(const Vide
{
if (!openInput(videoToOpen))
return { nullptr, 0};
openContext();
if (!openContext())
return { nullptr, 0};
int audioStreamIndex = findAudioStream();
if (audioStreamIndex == -1)
@ -653,7 +676,9 @@ std::unique_ptr<IVideoInstance> CVideoPlayer::open(const VideoPath & name, float
if (!result->openInput(name))
return nullptr;
result->openVideo();
if (!result->openVideo())
return nullptr;
result->prepareOutput(scaleFactor, false);
result->loadNextFrame(); // prepare 1st frame

View File

@ -42,7 +42,7 @@ class FFMpegStream : boost::noncopyable
AVFrame * frame = nullptr;
protected:
void openContext();
bool openContext();
void openCodec(int streamIndex);
int findVideoStream() const;
@ -91,7 +91,7 @@ public:
CVideoInstance();
~CVideoInstance();
void openVideo();
bool openVideo();
bool loadNextFrame();
double timeStamp() final;

View File

@ -350,7 +350,7 @@ EUpscalingFilter ScreenHandler::loadUpscalingFilter() const
};
auto filterName = settings["video"]["upscalingFilter"].String();
auto filter = upscalingFilterTypes.at(filterName);
auto filter = upscalingFilterTypes.count(filterName) ? upscalingFilterTypes.at(filterName) : EUpscalingFilter::AUTO;
if (filter != EUpscalingFilter::AUTO)
return filter;

View File

@ -262,10 +262,16 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, PlayerColor play
{
// use more compact form for right-click popup with no buttons / components
if(ret->text->slider)
{
ret->text->resize(Point(ret->text->pos.w, std::min(ret->text->label->textSize.y, RIGHT_CLICK_POPUP_MAX_HEIGHT_TEXTONLY)));
ret->pos.w = std::max(RIGHT_CLICK_POPUP_MIN_SIZE, ret->text->pos.w + 2 * SIDE_MARGIN);
ret->pos.h = std::max(RIGHT_CLICK_POPUP_MIN_SIZE, ret->text->pos.h + TOP_MARGIN + BOTTOM_MARGIN);
ret->pos.w = std::max(RIGHT_CLICK_POPUP_MIN_SIZE, ret->text->pos.w + 2 * SIDE_MARGIN);
ret->pos.h = std::max(RIGHT_CLICK_POPUP_MIN_SIZE, ret->text->pos.h + TOP_MARGIN + BOTTOM_MARGIN);
}
else
{
ret->pos.w = std::max(RIGHT_CLICK_POPUP_MIN_SIZE, ret->text->label->textSize.x + 2 * SIDE_MARGIN);
ret->pos.h = std::max(RIGHT_CLICK_POPUP_MIN_SIZE, ret->text->label->textSize.y + TOP_MARGIN + BOTTOM_MARGIN);
}
}
else
{

View File

@ -44,7 +44,9 @@
"startingStackChances" : { "type" : "array" },
"backpackSize" : { "type" : "number" },
"tavernInvite" : { "type" : "boolean" },
"minimalPrimarySkills" : { "type" : "array" }
"minimalPrimarySkills" : { "type" : "array" },
"movementPointsLand" : { "type" : "array" },
"movementPointsSea" : { "type" : "array" }
}
},
"towns" : {

View File

@ -359,6 +359,8 @@ CUnitState & CUnitState::operator=(const CUnitState & other)
waiting = other.waiting;
waitedThisTurn = other.waitedThisTurn;
casts = other.casts;
counterAttacks = other.counterAttacks;
shots = other.shots;
health = other.health;
cloneID = other.cloneID;
position = other.position;

View File

@ -34,6 +34,19 @@ protected:
{
std::atomic<int64_t> version = 0;
std::atomic<int64_t> value = 0;
BonusCacheEntry() = default;
BonusCacheEntry(const BonusCacheEntry & other)
: version(other.version.load())
, value(other.value.load())
{
}
BonusCacheEntry & operator =(const BonusCacheEntry & other)
{
version = other.version.load();
value = other.value.load();
return *this;
}
};
int getBonusValueImpl(BonusCacheEntry & currentValue, const CSelector & selector, BonusCacheMode) const;

View File

@ -35,6 +35,21 @@
VCMI_LIB_NAMESPACE_BEGIN
std::string JsonRandomizationException::cleanupJson(const JsonNode & value)
{
std::string result = value.toCompactString();
for (size_t i = 0; i < result.size(); ++i)
if (result[i] == '\n')
result[i] = ' ';
return result;
}
JsonRandomizationException::JsonRandomizationException(const std::string & message, const JsonNode & input)
: std::runtime_error(message + " Input was: " + cleanupJson(input))
{}
si32 JsonRandom::loadVariable(const std::string & variableGroup, const std::string & value, const Variables & variables, si32 defaultValue)
{
if (value.empty() || value[0] != '@')
@ -483,7 +498,10 @@ VCMI_LIB_NAMESPACE_BEGIN
if (!potentialPicks.empty())
pickedCreature = *RandomGeneratorUtil::nextItem(potentialPicks, rng);
else
logMod->warn("Failed to select suitable random creature!");
throw JsonRandomizationException("No potential creatures to pick!", value);
if (!pickedCreature.hasValue())
throw JsonRandomizationException("Invalid creature picked!", value);
stack.setType(pickedCreature.toCreature());
stack.count = loadValue(value, rng, variables);

View File

@ -27,6 +27,13 @@ struct Bonus;
struct Component;
class CStackBasicDescriptor;
class JsonRandomizationException : public std::runtime_error
{
std::string cleanupJson(const JsonNode & value);
public:
JsonRandomizationException(const std::string & message, const JsonNode & input);
};
class JsonRandom : public GameCallbackHolder
{
public:

View File

@ -11,6 +11,7 @@
#include "CRewardableConstructor.h"
#include "../json/JsonUtils.h"
#include "../json/JsonRandom.h"
#include "../mapObjects/CRewardableObject.h"
#include "../texts/CGeneralTextHandler.h"
#include "../IGameCallback.h"
@ -49,7 +50,14 @@ Rewardable::Configuration CRewardableConstructor::generateConfiguration(IGameCal
{
Rewardable::Configuration result;
result.variables.preset = presetVariables;
objectInfo.configureObject(result, rand, cb);
try {
objectInfo.configureObject(result, rand, cb);
}
catch (const JsonRandomizationException & e)
{
throw std::runtime_error("Failed to generate configuration for object '" + getJsonKey() + "'! Reason: " + e.what());
}
for(auto & rewardInfo : result.info)
{

View File

@ -500,7 +500,7 @@ std::vector<std::string> CIdentifierStorage::getModsWithFailedRequests() const
std::vector<std::string> result;
for (const auto & request : failedRequests)
if (!vstd::contains(result, request.localScope))
if (!vstd::contains(result, request.localScope) && ModScope::isScopeReserved(request.localScope))
result.push_back(request.localScope);
return result;