Skip to content

Commit b07b94d

Browse files
authored
feat: fix RemoteCall completely (#19)
1 parent 2db84d8 commit b07b94d

File tree

5 files changed

+843
-43
lines changed

5 files changed

+843
-43
lines changed

src/legacy/api/RemoteCallAPI.cpp

Lines changed: 216 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,194 @@
1-
#include "api/APIHelp.h"
1+
#include "RemoteCallAPI.h"
2+
3+
#include "api/BaseAPI.h"
4+
#include "api/BlockAPI.h"
5+
#include "api/BlockEntityAPI.h"
6+
#include "api/ContainerAPI.h"
7+
#include "api/EntityAPI.h"
8+
#include "api/ItemAPI.h"
29
#include "api/LlAPI.h"
10+
#include "api/NbtAPI.h"
11+
#include "api/PlayerAPI.h"
312
#include "engine/GlobalShareData.h"
413
#include "engine/MessageSystem.h"
14+
#include "legacyapi/remotecall/RemoteCallAPI.h"
515
#include "ll/api/service/ServerInfo.h"
616

17+
#include <map>
718
#include <process.h>
19+
#include <sstream>
820
#include <string>
921

1022
#define DEFAULT_REMOTE_CALL_NAME_SPACE "LLSEGlobal"
23+
#define logger lse::getSelfPluginInstance().getLogger()
24+
25+
//////////////////// Remote Call ////////////////////
26+
27+
RemoteCall::ValueType pack(Local<Value> value);
28+
RemoteCall::ValueType pack(Local<Object> value) {
29+
// Player*, Actor*, ItemStack*, Block*, BlockActor*, Container*, Vec3, BlockPos, CompoundTag*
30+
if (IsInstanceOf<PlayerClass>(value)) return PlayerClass::extract(value);
31+
if (IsInstanceOf<EntityClass>(value)) return EntityClass::extract(value);
32+
if (IsInstanceOf<ItemClass>(value)) return ItemClass::extract(value);
33+
if (IsInstanceOf<BlockClass>(value)) {
34+
auto block = EngineScope::currentEngine()->getNativeInstance<BlockClass>(value);
35+
return block->get();
36+
}
37+
if (IsInstanceOf<BlockEntityClass>(value)) return BlockEntityClass::extract(value);
38+
if (IsInstanceOf<ContainerClass>(value)) return ContainerClass::extract(value);
39+
if (IsInstanceOf<FloatPos>(value)) {
40+
auto pos = FloatPos::extractPos(value);
41+
return std::make_pair(pos->getVec3(), pos->getDimensionId());
42+
}
43+
if (IsInstanceOf<IntPos>(value)) {
44+
auto pos = IntPos::extractPos(value);
45+
return std::make_pair(pos->getBlockPos(), pos->getDimensionId());
46+
}
47+
if (IsInstanceOf<NbtCompoundClass>(value)) return NbtCompoundClass::extract(value);
48+
std::unordered_map<std::string, RemoteCall::ValueType> result;
49+
for (auto& k : value.getKeyNames()) result.emplace(k, pack(value.get(k)));
50+
return std::move(result);
51+
}
52+
RemoteCall::ValueType pack(Local<Array> value) {
53+
std::vector<RemoteCall::ValueType> result;
54+
for (size_t index = 0ULL, mEnd = value.size(); index < mEnd; ++index) {
55+
result.push_back(pack(value.get(index)));
56+
}
57+
return std::move(result);
58+
}
59+
60+
RemoteCall::ValueType pack(Local<Value> value) {
61+
switch (value.getKind()) {
62+
case script::ValueKind::kNull:
63+
return nullptr;
64+
break;
65+
case script::ValueKind::kObject:
66+
return pack(value.asObject());
67+
break;
68+
case script::ValueKind::kString:
69+
return value.toStr();
70+
break;
71+
case script::ValueKind::kNumber: {
72+
auto num = value.asNumber();
73+
return RemoteCall::NumberType(num.toInt64(), num.toDouble());
74+
break;
75+
}
76+
case script::ValueKind::kBoolean:
77+
return value.asBoolean().value();
78+
break;
79+
case script::ValueKind::kFunction:
80+
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: kFunction").c_str());
81+
break;
82+
case script::ValueKind::kArray:
83+
return pack(value.asArray());
84+
break;
85+
case script::ValueKind::kByteBuffer:
86+
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: kByteBuffer").c_str());
87+
return value.asByteBuffer().describeUtf8();
88+
break;
89+
case script::ValueKind::kUnsupported:
90+
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: kUnsupported").c_str());
91+
break;
92+
default:
93+
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: Unknown").c_str());
94+
break;
95+
}
96+
return RemoteCall::ValueType();
97+
}
98+
99+
// Player*, Actor*, ItemStack*, Block*, BlockActor*, Container*, Vec3, BlockPos, CompoundTag*
100+
Local<Value> _extractValue(bool v) { return Boolean::newBoolean(v); };
101+
Local<Value> _extractValue(std::string v) { return String::newString(v); };
102+
Local<Value> _extractValue(std::nullptr_t v) { return Local<Value>(); };
103+
Local<Value> _extractValue(std::string* v) { return Local<Value>(); };
104+
Local<Value> _extractValue(Player* v) { return PlayerClass::newPlayer(v); };
105+
Local<Value> _extractValue(Actor* v) { return EntityClass::newEntity(v); };
106+
Local<Value> _extractValue(Block* v) { return BlockClass::newBlock(v, &BlockPos::ZERO, -1); };
107+
Local<Value> _extractValue(BlockActor* const& v) { return BlockEntityClass::newBlockEntity(v, -1); };
108+
Local<Value> _extractValue(Container* v) { return ContainerClass::newContainer(v); };
109+
Local<Value> _extractValue(RemoteCall::WorldPosType v) { return FloatPos::newPos(v.pos, v.dimId); };
110+
Local<Value> _extractValue(RemoteCall::BlockPosType v) { return IntPos::newPos(v.pos, v.dimId); };
111+
Local<Value> _extractValue(RemoteCall::BlockType v) {
112+
return BlockClass::newBlock(v.get<Block const*>(), &v.blockPos, v.dimension);
113+
};
114+
Local<Value> _extractValue(RemoteCall::NumberType v) { return Number::newNumber(v.get<double>()); };
115+
Local<Value> _extractValue(RemoteCall::ItemType&& v) {
116+
if (v.own) return ItemClass::newItem(v.tryGetUniquePtr().release(), false);
117+
else return ItemClass::newItem(const_cast<ItemStack*>(v.ptr), false);
118+
};
119+
Local<Value> _extractValue(RemoteCall::NbtType&& v) {
120+
if (v.own) return NbtCompoundClass::pack(v.tryGetUniquePtr());
121+
else return NbtCompoundClass::pack(const_cast<CompoundTag*>(v.ptr), false);
122+
};
123+
124+
Local<Value> extract(RemoteCall::ValueType&& val);
125+
126+
Local<Value> extractValue(RemoteCall::Value&& val) {
127+
static_assert(std::variant_size_v<RemoteCall::Value> == 13);
128+
switch (val.index()) {
129+
#define Extra(index) \
130+
case index: \
131+
return _extractValue(std::move(std::get<index>(val)));
132+
Extra(0);
133+
Extra(1);
134+
Extra(2);
135+
Extra(3);
136+
Extra(4);
137+
Extra(5);
138+
Extra(6);
139+
Extra(7);
140+
Extra(8);
141+
Extra(9);
142+
Extra(10);
143+
Extra(11);
144+
Extra(12);
145+
default:
146+
throw std::exception("Unsupported Type!");
147+
break;
148+
}
149+
};
150+
Local<Value> extractValue(std::vector<RemoteCall::ValueType>&& val) {
151+
auto arr = Array::newArray();
152+
for (auto& v : val) arr.add(extract(std::move(v)));
153+
return arr;
154+
};
155+
Local<Value> extractValue(std::unordered_map<std::string, RemoteCall::ValueType>&& val) {
156+
auto obj = Object::newObject();
157+
for (auto& [k, v] : val) {
158+
obj.set(k, extract(std::move(v)));
159+
}
160+
return obj;
161+
};
162+
163+
Local<Value> extract(RemoteCall::ValueType&& val) {
164+
static_assert(std::variant_size_v<RemoteCall::ValueType::Type> == 3);
165+
switch (val.value.index()) {
166+
case 0:
167+
return extractValue(std::move(std::get<0>(val.value)));
168+
case 1:
169+
return extractValue(std::move(std::get<1>(val.value)));
170+
case 2:
171+
return extractValue(std::move(std::get<2>(val.value)));
172+
default:
173+
throw std::exception("Unsupported Type");
174+
return Local<Value>();
175+
break;
176+
}
177+
}
11178

12179
Local<Value> MakeRemoteCall(const string& nameSpace, const string& funcName, const Arguments& args) {
13-
auto data = globalShareData->exportedFuncs.find(nameSpace + ":" + funcName);
14-
if (data == globalShareData->exportedFuncs.end()) {
15-
lse::getSelfPluginInstance().getLogger().error(
16-
"Fail to import! Function [{}::{}] has not been exported!",
17-
nameSpace,
18-
funcName
19-
);
20-
lse::getSelfPluginInstance().getLogger().error("In plugin <{}>", ENGINE_OWN_DATA()->pluginName);
180+
auto& func = RemoteCall::importFunc(nameSpace, funcName);
181+
if (!func) {
182+
logger.error("Fail to import! Function [{}::{}] has not been exported!", nameSpace, funcName);
183+
logger.error("In plugin <{}>", ENGINE_OWN_DATA()->pluginName);
21184
return Local<Value>();
22185
}
23186

24-
std::vector<std::string> params;
187+
std::vector<RemoteCall::ValueType> params;
25188
for (int i = 0; i < args.size(); ++i) {
26-
params.emplace_back(ValueToJson(args[i]));
189+
params.emplace_back(pack(args[i]));
27190
}
28-
return JsonToValue(data->second.callback(std::move(params)));
191+
return extract(func(std::move(params)));
29192
}
30193

31194
bool LLSEExportFunc(
@@ -34,35 +197,52 @@ bool LLSEExportFunc(
34197
const string& nameSpace,
35198
const string& funcName
36199
) {
37-
std::string exportName = nameSpace + ":" + funcName;
38-
ExportedFuncData* funcData = &(globalShareData->exportedFuncs)[exportName];
39-
if (funcData->engine) return false;
40-
funcData->engine = engine;
41-
funcData->func = script::Global<Function>(func);
42-
funcData->fromEngineType = LLSE_MODULE_TYPE;
43-
funcData->callback = [exportName](std::vector<std::string> params) -> std::string {
44-
auto data = globalShareData->exportedFuncs.find(exportName);
45-
if (data == globalShareData->exportedFuncs.end()) {
46-
lse::getSelfPluginInstance().getLogger().error("Exported function \"{}\" not found", exportName);
47-
return "";
48-
}
49-
auto engine = data->second.engine;
50-
if ((ll::getServerStatus() != ll::ServerStatus::Running) || !EngineManager::isValid(engine)
200+
// Putting script::Global value into lambda capture list may cause crash
201+
// script::Global<Function> callback = script::Global<Function>(func);
202+
std::string identifier = nameSpace + "::" + funcName;
203+
RemoteCall::CallbackFn cb = [engine, identifier /*, scriptCallback = std::move(callback)*/](
204+
std::vector<RemoteCall::ValueType> params
205+
) -> RemoteCall::ValueType {
206+
if (ll::getServerStatus() != ll::ServerStatus::Stopping || !EngineManager::isValid(engine)
51207
|| engine->isDestroying())
52208
return "";
53-
EngineScope enter(data->second.engine);
54-
std::vector<script::Local<Value>> scriptParams;
55-
for (auto& param : params) {
56-
scriptParams.emplace_back(JsonToValue(param));
209+
EngineScope enter(engine);
210+
try {
211+
auto iter = ENGINE_GET_DATA(engine)->exportFuncs.find(identifier);
212+
if (iter == ENGINE_GET_DATA(engine)->exportFuncs.end()) {
213+
logger.debug("");
214+
return "";
215+
}
216+
auto scriptCallback = iter->second.callback.get();
217+
std::vector<script::Local<Value>> scriptParams;
218+
for (auto& param : params) {
219+
scriptParams.emplace_back(extract(std::move(param)));
220+
}
221+
return pack(scriptCallback.call({}, scriptParams));
57222
}
58-
return ValueToJson(data->second.func.get().call({}, scriptParams));
223+
CATCH_WITHOUT_RETURN("Fail in Remote Call");
224+
return "";
59225
};
60-
return true;
226+
if (RemoteCall::exportFunc(nameSpace, funcName, std::move(cb))) {
227+
ENGINE_GET_DATA(engine)->exportFuncs.emplace(
228+
identifier,
229+
RemoteCallData{nameSpace, funcName, script::Global<Function>(func)}
230+
);
231+
return true;
232+
}
233+
return false;
61234
}
62235

63236
bool LLSERemoveAllExportedFuncs(ScriptEngine* engine) {
64-
globalShareData->exportedFuncs.clear();
65-
return true;
237+
// enter scope to prevent crash in script::Global::~Global()
238+
EngineScope enter(engine);
239+
std::vector<std::pair<std::string, std::string>> funcs;
240+
for (auto& [key, data] : ENGINE_GET_DATA(engine)->exportFuncs) {
241+
funcs.emplace_back(data.nameSpace, data.funcName);
242+
}
243+
int count = RemoteCall::removeFuncs(std::move(funcs));
244+
ENGINE_GET_DATA(engine)->exportFuncs.clear();
245+
return count;
66246
}
67247

68248
//////////////////// APIs ////////////////////
@@ -130,9 +310,8 @@ Local<Value> LlClass::hasFuncExported(const Arguments& args) {
130310
funcName = args[0].toStr();
131311
}
132312

133-
return Boolean::newBoolean(
134-
globalShareData->exportedFuncs.find(nameSpace + ":" + funcName) != globalShareData->exportedFuncs.end()
135-
);
313+
// 远程调用
314+
return Boolean::newBoolean(RemoteCall::hasFunc(nameSpace, funcName));
136315
}
137316
CATCH("Fail in LLSEHasExported!")
138317
}

src/legacy/api/RemoteCallAPI.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#pragma once
2+
#include "api/APIHelp.h"

src/legacy/engine/EngineOwnData.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ struct FormCallbackData {
1717
script::Global<script::Function> func;
1818
};
1919

20-
// struct RemoteCallData {
21-
// std::string nameSpace;
22-
// std::string funcName;
23-
// script::Global<Function> callback;
24-
// };
20+
struct RemoteCallData {
21+
std::string nameSpace;
22+
std::string funcName;
23+
script::Global<Function> callback;
24+
};
2525

2626
/*
2727
struct SimpleCallbackData
@@ -44,7 +44,7 @@ struct EngineOwnData {
4444
std::map<unsigned, FormCallbackData> formCallbacks;
4545

4646
// RemoteCall Exported Functions: unordered_map<nameSpace, funcName>
47-
// std::unordered_map<std::string, RemoteCallData> exportFuncs;
47+
std::unordered_map<std::string, RemoteCallData> exportFuncs;
4848

4949
/*
5050
uint64_t simpleCallbackIndex = 0;

0 commit comments

Comments
 (0)