1 #include "hook_api.h"
2 
3 #include "globalincs/pstypes.h"
4 
5 #include <utility>
6 
7 namespace scripting {
8 
9 namespace {
10 
11 class HookManager {
12   public:
addHook(HookBase * hook)13 	int32_t addHook(HookBase* hook)
14 	{
15 		Assertion(std::find_if(_hooks.cbegin(),
16 							   _hooks.cend(),
17 							   [hook](const HookBase* test) { return test->getHookName() == hook->getHookName(); }) ==
18 					  _hooks.cend(),
19 				  "Hook '%s' already exists!",
20 				  hook->getHookName().c_str());
21 
22 		const auto id = ++_lastId;
23 		_hooks.push_back(hook);
24 		return id;
25 	}
26 
addHookWithId(HookBase * hook)27 	void addHookWithId(HookBase* hook)
28 	{
29 		Assertion(std::find_if(_hooks.cbegin(),
30 							   _hooks.cend(),
31 							   [hook](const HookBase* test) { return test->getHookName() == hook->getHookName(); }) ==
32 					  _hooks.cend(),
33 				  "Hook '%s' already exists!",
34 				  hook->getHookName().c_str());
35 
36 		_hooks.push_back(hook);
37 	}
38 
getHooks() const39 	const SCP_vector<HookBase*>& getHooks() const { return _hooks; }
40 
41   private:
42 	int32_t _lastId = CHA_LAST;
43 	SCP_vector<HookBase*> _hooks;
44 };
45 
getHookManager()46 HookManager& getHookManager()
47 {
48 	static HookManager mgr;
49 	return mgr;
50 }
51 } // namespace
52 
53 namespace detail {
convert_arg_type(object * objp)54 ade_odata_setter<object_h> convert_arg_type(object* objp)
55 {
56 	return ade_object_to_odata(objp != nullptr ? OBJ_INDEX(objp) : -1);
57 }
58 } // namespace detail
59 
HookVariableDocumentation(const char * name_,ade_type_info type_,const char * description_)60 HookVariableDocumentation::HookVariableDocumentation(const char* name_, ade_type_info type_, const char* description_)
61 	: name(name_), type(std::move(type_)), description(description_)
62 {
63 }
64 
HookBase(SCP_string hookName,SCP_string description,SCP_vector<HookVariableDocumentation> parameters,int32_t hookId)65 HookBase::HookBase(SCP_string hookName,
66 				   SCP_string description,
67 				   SCP_vector<HookVariableDocumentation> parameters,
68 				   int32_t hookId)
69 	: _hookName(std::move(hookName)), _description(std::move(description)), _parameters(std::move(parameters))
70 {
71 	// If we specify a forced id then use that. This is for special hooks that need a guaranteed id
72 	if (hookId >= 0) {
73 		_hookId = hookId;
74 		getHookManager().addHookWithId(this);
75 	} else {
76 		_hookId = getHookManager().addHook(this);
77 	}
78 }
79 
getHookName() const80 const SCP_string& HookBase::getHookName() const { return _hookName; }
getDescription() const81 const SCP_string& HookBase::getDescription() const { return _description; }
getParameters() const82 const SCP_vector<HookVariableDocumentation>& HookBase::getParameters() const { return _parameters; }
getHookId() const83 int32_t HookBase::getHookId() const { return _hookId; }
84 HookBase::~HookBase() = default;
85 
Factory(SCP_string hookName,SCP_string description,SCP_vector<HookVariableDocumentation> parameters,int32_t hookId)86 std::shared_ptr<Hook> Hook::Factory(SCP_string hookName,
87 									SCP_string description,
88 									SCP_vector<HookVariableDocumentation> parameters,
89 									int32_t hookId)
90 {
91 	return std::make_shared<Hook>(std::move(hookName), std::move(description), std::move(parameters), hookId);
92 }
Factory(SCP_string hookName,int32_t hookId)93 std::shared_ptr<Hook> Hook::Factory(SCP_string hookName, int32_t hookId)
94 {
95 	return std::make_shared<Hook>(std::move(hookName), SCP_string(), SCP_vector<HookVariableDocumentation>(), hookId);
96 }
Hook(SCP_string hookName,SCP_string description,SCP_vector<HookVariableDocumentation> parameters,int32_t hookId)97 Hook::Hook(SCP_string hookName,
98 		   SCP_string description,
99 		   SCP_vector<HookVariableDocumentation> parameters,
100 		   int32_t hookId)
101 	: HookBase(std::move(hookName), std::move(description), std::move(parameters), hookId)
102 {
103 }
104 Hook::~Hook() = default;
105 
isOverridable() const106 bool Hook::isOverridable() const { return false; }
107 
OverridableHook(SCP_string hookName,SCP_string description,SCP_vector<HookVariableDocumentation> parameters,int32_t hookId)108 OverridableHook::OverridableHook(SCP_string hookName,
109 								 SCP_string description,
110 								 SCP_vector<HookVariableDocumentation> parameters,
111 								 int32_t hookId)
112 	: Hook(std::move(hookName), std::move(description), std::move(parameters), hookId)
113 {
114 }
115 OverridableHook::~OverridableHook() = default;
116 
Factory(SCP_string hookName,SCP_string description,SCP_vector<HookVariableDocumentation> parameters,int32_t hookId)117 std::shared_ptr<OverridableHook> OverridableHook::Factory(SCP_string hookName,
118 														  SCP_string description,
119 														  SCP_vector<HookVariableDocumentation> parameters,
120 														  int32_t hookId)
121 {
122 	return std::make_shared<OverridableHook>(std::move(hookName),
123 											 std::move(description),
124 											 std::move(parameters),
125 											 hookId);
126 }
isOverridable() const127 bool OverridableHook::isOverridable() const { return true; }
128 
getHooks()129 const SCP_vector<HookBase*>& getHooks() { return getHookManager().getHooks(); }
130 
131 } // namespace scripting
132