载入中...
搜索中...
未找到
EditorExtension.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <exception>
5
6namespace eve::editor {
7
9 if (!commands_)
10 return invalid("editor.extension.missing-command-service", "Extension registry has no command service");
11 const std::string owner = extension.ownerModule();
12 if (owner.empty()) return invalid("editor.extension.missing-owner", "Game editor extension owner is required");
13 if (std::any_of(commandVisibility_.begin(), commandVisibility_.end(),
14 [&](const CommandVisibility& command) { return command.ownerModule == owner; }) ||
15 std::any_of(tools_.begin(), tools_.end(),
16 [&](const ExtensionToolDescriptor& tool) { return tool.ownerModule == owner; }))
17 return invalid("editor.extension.duplicate-owner", "Game editor extension owner is already loaded");
18 activeOwner_ = owner;
19 try {
20 extension.registerEditor(*this);
21 } catch (const std::exception& exception) {
22 unload(owner);
23 activeOwner_.clear();
24 return invalid("editor.extension.exception", exception.what());
25 } catch (...) {
26 unload(owner);
27 activeOwner_.clear();
28 return invalid("editor.extension.exception", "Game editor extension threw an unknown exception");
29 }
30 activeOwner_.clear();
31 return eve::editing::applied<void>();
32}
33
34std::size_t EditorExtensionRegistry::unload(const std::string& ownerModule) {
35 std::size_t removed = commands_ ? commands_->unregisterOwner(ownerModule) : 0;
36 auto eraseOwner = [&](auto& values) {
37 const std::size_t before = values.size();
38 std::erase_if(values, [&](const auto& value) { return value.ownerModule == ownerModule; });
39 removed += before - values.size();
40 };
41 eraseOwner(commandVisibility_);
42 eraseOwner(tools_);
43 eraseOwner(palettes_);
44 eraseOwner(rules_);
45 return removed;
46}
47
49 const ExtensionAudience audience = audienceFor(profile);
50 for (const CommandVisibility& command : commandVisibility_)
51 if (hasAudience(command.audiences, audience)) profile.allowCommand(command.id);
52}
53
54std::vector<ExtensionToolDescriptor> EditorExtensionRegistry::tools(const HostProfile& profile) const {
55 std::vector<ExtensionToolDescriptor> result;
56 const ExtensionAudience audience = audienceFor(profile);
57 for (const ExtensionToolDescriptor& tool : tools_)
58 if (hasAudience(tool.audiences, audience)) result.push_back(tool);
59 return result;
60}
61
62std::vector<ExtensionPaletteDescriptor> EditorExtensionRegistry::palettes(const HostProfile& profile) const {
63 std::vector<ExtensionPaletteDescriptor> result;
64 const ExtensionAudience audience = audienceFor(profile);
65 for (const ExtensionPaletteDescriptor& palette : palettes_)
66 if (hasAudience(palette.audiences, audience)) result.push_back(palette);
67 return result;
68}
69
70std::vector<ExtensionRuleDescriptor> EditorExtensionRegistry::rules(const HostProfile& profile) const {
71 std::vector<ExtensionRuleDescriptor> result;
72 const ExtensionAudience audience = audienceFor(profile);
73 for (const ExtensionRuleDescriptor& rule : rules_)
74 if (hasAudience(rule.audiences, audience)) result.push_back(rule);
75 return result;
76}
77
80 ExtensionAudience audiences) {
81 if (activeOwner_.empty())
82 return eve::editing::failed<EditorValue>(EditorStatus::Rejected,
83 RuleId("editor.extension.registration-outside-load"),
84 "Commands may only be registered while loading an extension");
85 descriptor.ownerModule = activeOwner_;
86 Result<EditorValue> result = commands_->registerCommand(descriptor, std::move(handler));
87 if (result.ok()) commandVisibility_.push_back({descriptor.id, activeOwner_, audiences});
88 return result;
89}
90
92 if (activeOwner_.empty() || descriptor.id.empty())
93 return invalid("editor.extension.invalid-tool", "Tool registration requires an active owner and id");
94 if (std::any_of(tools_.begin(), tools_.end(),
95 [&](const ExtensionToolDescriptor& tool) { return tool.id == descriptor.id; }))
96 return invalid("editor.extension.duplicate-tool", "Tool id is already registered");
97 descriptor.ownerModule = activeOwner_;
98 tools_.push_back(std::move(descriptor));
99 return eve::editing::applied<void>();
100}
101
103 if (activeOwner_.empty() || descriptor.id.empty())
104 return invalid("editor.extension.invalid-palette", "Palette registration requires an active owner and id");
105 descriptor.ownerModule = activeOwner_;
106 palettes_.push_back(std::move(descriptor));
107 return eve::editing::applied<void>();
108}
109
111 if (activeOwner_.empty() || descriptor.id.empty())
112 return invalid("editor.extension.invalid-rule", "Rule registration requires an active owner and id");
113 descriptor.ownerModule = activeOwner_;
114 rules_.push_back(std::move(descriptor));
115 return eve::editing::applied<void>();
116}
117
118ExtensionAudience EditorExtensionRegistry::audienceFor(const HostProfile& profile) {
119 switch (profile.kind()) {
120 case HostKind::Developer: return ExtensionAudience::Developer;
121 case HostKind::RuntimeBuilder: return ExtensionAudience::Player;
122 case HostKind::RuntimeAdmin: return ExtensionAudience::Admin;
123 case HostKind::Automation: return ExtensionAudience::Automation;
124 }
126}
127
128Result<void> EditorExtensionRegistry::invalid(const char* rule, std::string message) {
129 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId(rule), std::move(message));
130}
131
132} // namespace eve::editor
double value
std::string descriptor
std::map< std::string, Var > values
std::string palette
std::string message
HSQOBJECT handler
int removed
Move-only operation result carrying either a value or Status.
Definition Result.h:155
bool ok() const noexcept
Whether this result represents a non-failure outcome.
Definition Result.h:255
size_t unregisterOwner(const std::string &ownerModule)
Remove every command registered by a module.
Result< EditorValue > registerCommand(CommandDescriptor descriptor, EditorCommandHandler handler, bool replace=false)
Register one command.
Result< void > registerPalette(ExtensionPaletteDescriptor descriptor) override
Registers palette.
Result< void > load(IGameEditorExtension &extension)
Load one extension under its stable owner module.
std::vector< ExtensionToolDescriptor > tools(const HostProfile &profile) const
Return tool descriptors visible to a host.
Result< EditorValue > registerCommand(CommandDescriptor descriptor, EditorCommandHandler handler, ExtensionAudience audiences) override
Registers command.
std::vector< ExtensionRuleDescriptor > rules(const HostProfile &profile) const
Return validation descriptors visible to a host.
std::vector< ExtensionPaletteDescriptor > palettes(const HostProfile &profile) const
Return palette descriptors visible to a host.
std::size_t unload(const std::string &ownerModule)
Remove every component registered by an owner module.
Result< void > registerRule(ExtensionRuleDescriptor descriptor) override
Registers rule.
Result< void > registerTool(ExtensionToolDescriptor descriptor) override
Registers tool.
void configureProfile(HostProfile &profile) const
Add player/admin/automation extension commands to a deny-by-default profile.
Upper capability boundary for one editor host.
void allowCommand(CommandId id)
Allow command.
HostKind kind() const
Kind.
Entry point implemented by a gameplay module to inject editor behavior.
constexpr bool hasAudience(ExtensionAudience value, ExtensionAudience audience)
True when audience.
std::function< Result< EditorValue >(const CommandContext &, const EditorValue &)> EditorCommandHandler
eve::editing::RuleId RuleId
Definition EditorIds.h:32
ExtensionAudience
Host audiences to which a game-provided editor extension may be published.
Presentation and execution metadata for a registered command.
Semantic palette that can place the same tool differently per audience.
Discoverable gameplay validation rule registered by a game extension.
Host-neutral metadata for a game-provided editor tool.