mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-25 21:38:59 +02:00
commit
f8312737bb
@ -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"
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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" : {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user