载入中...
搜索中...
未找到
PcgPhotoModeApplyPlan.cpp
浏览该文件的文档.
2#include "common/Capability.h"
3#include "common/AudioQuery.h"
7#include <simplesquirrel/simplesquirrel.hpp>
8#include <unordered_set>
9
10namespace eve::ui {
11namespace {
12PhotoModeDomain domainFor(const std::string& n) {
13 static const std::unordered_set<std::string> framePacing={"m_vSync","m_targetFPS"};
14 static const std::unordered_set<std::string> graphics={"m_lodBias","m_antiAliasing","m_shadowDistance","m_shadowResolution","m_shadowCascades"};
15 static const std::unordered_set<std::string> camera={"m_fieldOfView","m_pcgCullinDistance","m_cameraAperture","m_cameraFocalLength","m_cameraRoll","m_farClipPlane"};
16 static const std::unordered_set<std::string> streaming={"m_pcgLoadRange","m_pcgImpostorRange"};
17 static const std::unordered_set<std::string> audio={"m_globalVolume","m_pcgUnderwaterVolume"};
18 if(framePacing.contains(n))return PhotoModeDomain::FramePacing;
19 if(graphics.contains(n))return PhotoModeDomain::Graphics;
20 if(camera.contains(n))return PhotoModeDomain::Camera;
21 if(streaming.contains(n))return PhotoModeDomain::Streaming;
22 if(audio.contains(n))return PhotoModeDomain::Audio;
23 if(n.starts_with("m_pcgWeather")||n.starts_with("m_pcgWind"))return PhotoModeDomain::Weather;
24 if(n.starts_with("m_pcgWater")||n.starts_with("m_pcgReflections")||n.starts_with("m_pcgUnderwaterFog"))return PhotoModeDomain::Water;
25 if(n.starts_with("m_postFX")||n.starts_with("m_dof")||n=="m_autoDOFFocus"||n=="m_savedDofFocusMode")return PhotoModeDomain::PostFx;
26 if(n.starts_with("m_terrain")||n=="m_drawInstanced")return PhotoModeDomain::Terrain;
27 if(n.starts_with("m_globalGrass")||n.starts_with("m_cameraCell"))return PhotoModeDomain::Grass;
28 if(n=="m_isUsingPcgLighting"||n=="m_selectedPcgLightingProfile"||n.starts_with("m_pcgTime")||
29 n.starts_with("m_pcgAdditional")||n.starts_with("m_sun")||n.starts_with("m_fog")||
30 n.starts_with("m_skybox")||n.starts_with("m_ambient")||n.starts_with("m_globalLight")||
31 n.starts_with("m_globalFog")||n.starts_with("m_globalShadow")||n.starts_with("m_overrideDensity")||
32 n.starts_with("m_densityVolume"))return PhotoModeDomain::Lighting;
34}
35class RegisteredPhotoModeSink final:public IPhotoModeApplySink {
36public:
37 Result<void> applyPhotoModeAssignment(const PhotoModeAssignment& assignment)override{
38 if(assignment.field=="m_globalVolume"){
39 auto* audio=cap::query<IAudioQuery>();
40 if(!audio)return Result<void>::failure(Diagnostic::error(DiagnosticCode::Unsupported,"audio capability is unavailable",{},{},"ui.pcgPhotoModeApply"));
41 auto* value=std::get_if<float>(&assignment.value);
42 if(!value)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"global volume requires a float value",{},{},"ui.pcgPhotoModeApply"));
43 audio->setVolume(*value);return Result<void>::success();
44 }
45 if(assignment.domain==PhotoModeDomain::FramePacing){
46 auto* value=std::get_if<int64_t>(&assignment.value);
47 if(!value)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"frame setting requires an integer value",{},{},"ui.pcgPhotoModeApply"));
48 if(assignment.field=="m_vSync"){
49 if(*value<0||*value>2)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"VSync count must be in [0,2]",{},{},"ui.pcgPhotoModeApply"));
50 auto* presentation=cap::query<IFramePresentation>();
51 if(!presentation)return Result<void>::failure(Diagnostic::error(DiagnosticCode::Unsupported,"frame presentation capability is unavailable",{},{},"ui.pcgPhotoModeApply"));
52 auto* pacing=cap::query<IFramePacing>();
53 if(!pacing)return Result<void>::failure(Diagnostic::error(DiagnosticCode::Unsupported,"frame pacing capability is unavailable",{},{},"ui.pcgPhotoModeApply"));
54 auto pacingResult=pacing->setVerticalSyncCount(static_cast<int>(*value));
55 if(!pacingResult.ok())return pacingResult;
56 presentation->setVSyncCount(static_cast<int>(*value));
57 return Result<void>::success();
58 }
59 if(assignment.field=="m_targetFPS"){
60 if(*value < -1 || *value > 240)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"target FPS must be in [-1,240]",{},{},"ui.pcgPhotoModeApply"));
61 auto* pacing=cap::query<IFramePacing>();
62 if(!pacing)return Result<void>::failure(Diagnostic::error(DiagnosticCode::Unsupported,"frame pacing capability is unavailable",{},{},"ui.pcgPhotoModeApply"));
63 return pacing->setTargetFramesPerSecond(static_cast<int>(*value));
64 }
65 return Result<void>::failure(Diagnostic::error(DiagnosticCode::Unsupported,"unknown frame setting: "+assignment.field,{},{},"ui.pcgPhotoModeApply"));
66 }
67 IPhotoModeFieldSink* selected=nullptr;
68 const size_t count=cap::listenerCount<IPhotoModeFieldSink>();
69 for(size_t i=0;i<count;++i){
70 auto* candidate=cap::listenerAt<IPhotoModeFieldSink>(i);
71 if(candidate&&candidate->acceptsPhotoModeField(assignment)==PhotoModeFieldAcceptance::Accepted){
72 if(selected)return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"multiple photo-mode providers accept field: "+assignment.field,{},{},"ui.pcgPhotoModeApply"));
73 selected=candidate;
74 }
75 }
76 if(!selected)return Result<void>::failure(Diagnostic::error(DiagnosticCode::Unsupported,"no photo-mode provider accepts field: "+assignment.field,{},{},"ui.pcgPhotoModeApply"));
77 return selected->applyPhotoModeField(assignment);
78 }
79private:
80 };
82 return std::visit([](const auto& v)->PhotoModeValue {
83 using T=std::decay_t<decltype(v)>;
84 if constexpr(std::is_same_v<T,PcgPhotoModeColor>)return PhotoModeColor{v.r,v.g,v.b,v.a};
85 else return v;
86 },value);
87}
88}
89
91 std::vector<Command> candidate;
92 for(uint64_t i=0;i<before.getFieldCount();++i){
93 auto name=before.getFieldName(i); if(!name.ok())return Result<void>::failure(name.status());
94 auto a=before.getValue(name.value()); if(!a.ok())return Result<void>::failure(a.status());
95 auto b=after.getValue(name.value()); if(!b.ok())return Result<void>::failure(b.status());
96 if(a.value()!=b.value())candidate.push_back({name.value(),domainFor(name.value()),convert(a.value()),convert(b.value())});
97 }
98 commands_=std::move(candidate); appliedCount_=0; rollbackComplete_=true; ++revision_;
99 return Result<void>::success();
100}
101Result<void> PcgPhotoModeApplyPlan::compileJson(const std::string& beforeJson,const std::string& afterJson) {
102 PcgPhotoModeValues before,after;
103 auto a=before.restoreJson(beforeJson);if(!a.ok())return Result<void>::failure(a.status());
104 auto b=after.restoreJson(afterJson);if(!b.ok())return Result<void>::failure(b.status());
105 return compile(before,after);
106}
108 appliedCount_=0; rollbackComplete_=true;
109 for(size_t i=0;i<commands_.size();++i){
110 auto result=sink.applyPhotoModeAssignment({commands_[i].field,commands_[i].domain,commands_[i].after});
111 if(!result.ok()){
112 bool restored=true;
113 for(size_t j=i;j>0;--j){
114 auto rollback=sink.applyPhotoModeAssignment({commands_[j-1].field,commands_[j-1].domain,commands_[j-1].before});
115 if(!rollback.ok())restored=false;
116 }
117 rollbackComplete_=restored;
118 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,restored?"photo-mode assignment failed; applied assignments were rolled back":
119 "photo-mode assignment failed and rollback was incomplete",{},{},"ui.pcgPhotoModeApply"));
120 }
121 ++appliedCount_;
122 }
123 ++revision_; return Result<void>::success();
124}
126 if(auto* sink=cap::query<IPhotoModeApplySink>())return execute(*sink);
127 RegisteredPhotoModeSink sink;return execute(sink);
128}
130 if(index>=commands_.size())return Result<std::string>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"photo-mode command index is out of range",{},{},"ui.pcgPhotoModeApply"));
131 return Result<std::string>::success(commands_[index].field);
132}
134 if(index>=commands_.size())return Result<int>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"photo-mode command index is out of range",{},{},"ui.pcgPhotoModeApply"));
135 return Result<int>::success(static_cast<int>(commands_[index].domain));
136}
138 auto vm=t.getHandle();auto c=t.addClass("PcgPhotoModeApplyPlan",ssq::Class::Ctor<PcgPhotoModeApplyPlan()>());
139 c.addFunc("compileJson",[vm](PcgPhotoModeApplyPlan*s,const std::string&a,const std::string&b){return script::projectResult(vm,s->compileJson(a,b));});
140 c.addFunc("executeRegistered",[vm](PcgPhotoModeApplyPlan*s){return script::projectResult(vm,s->executeRegistered());});
141 c.addFunc("getCommandCount",[](const PcgPhotoModeApplyPlan*s){return s->getCommandCount();});
142 c.addFunc("getCommandField",[vm](const PcgPhotoModeApplyPlan*s,uint64_t i){return script::projectResult(vm,s->getCommandField(i),[](const std::string&v){return v;});});
143 c.addFunc("getCommandDomain",[vm](const PcgPhotoModeApplyPlan*s,uint64_t i){return script::projectResult(vm,s->getCommandDomain(i),[](int v){return v;});});
144 c.addFunc("getAppliedCount",[](const PcgPhotoModeApplyPlan*s){return s->getAppliedCount();});
145 c.addFunc("getRollbackComplete",[](const PcgPhotoModeApplyPlan*s){return s->getRollbackComplete();});
146 c.addFunc("getRevision",[](const PcgPhotoModeApplyPlan*s){return s->getRevision();});
147}
148}
double value
OwnedAudio audio
const std::string & s
HSQUIRRELVM vm
Definition ECS.cpp:20
float camera[2]
glm::vec3 n
Definition Grass.cpp:63
float v
std::int32_t c
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float t
std::uint32_t count
The single Squirrel projection for common Result, Status and Value.
uint32_t index
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
IPhotoModeApplySink public API.
virtual Result< void > applyPhotoModeAssignment(const PhotoModeAssignment &assignment)=0
Apply one atomic assignment to its authoritative domain.
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Stable, reversible difference between two complete Pcg photo-mode snapshots.
Result< void > compile(const PcgPhotoModeValues &before, const PcgPhotoModeValues &after)
Compile all changed fields in source declaration order.
Result< std::string > getCommandField(uint64_t index) const
Return a command field name.
Result< void > executeRegistered()
Execute through the registered capability; absence is an observable failure.
Result< void > execute(IPhotoModeApplySink &sink)
Execute through an explicit sink and roll back prior writes after a failure.
Result< int > getCommandDomain(uint64_t index) const
Return a command domain.
Result< void > compileJson(const std::string &beforeJson, const std::string &afterJson)
Compile two schema-1 JSON snapshots atomically.
Complete typed value set from Pcg PhotoModeProfile with exact defaults.
Result< void > restoreJson(const std::string &json)
Atomically restore schema 1 JSON; unknown or missing fields are rejected.
uint64_t getFieldCount() const noexcept
Return stable schema field count.
Result< PcgPhotoModeValue > getValue(const std::string &name) const
Read a field as its schema-declared native variant.
Result< std::string > getFieldName(uint64_t index) const
Return schema field name by declaration order.
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
std::variant< bool, int64_t, float, std::string, PcgPhotoModeColor > PcgPhotoModeValue
void exposePcgPhotoModeApplyPlanBindings(ssq::Table &t)
Register Pcg photo-mode application-plan bindings.
std::variant< bool, std::int64_t, float, std::string, PhotoModeColor > PhotoModeValue
Typed payload accepted by authoritative photo-mode domain owners.
PhotoModeDomain
Authoritative owner selected for a Pcg photo-mode field.