Introduce a pbproxy library to solve macOS linker issues.
On SDKs which use protobufs, the engine has objects compiled against a specific version of protobuf. Normally this is fine, we take care on Linux to use the same C++ ABI. On macOS however, we use libc++ to enable C++11 functionality, whereas the protobuf library has been compiled with libstc++. These ABIs are not compatible. To address the problem, we introduce PbHandle. PbHandle is a wrapper around protobuf::Message with two added pieces of state: whether or not the handle "owns" the message (and can free it in its destructor), and whether or not the handle was created by the engine (private) or created by SourceMod (local). Whenever we transfer a protobuf::Message pointer to SourceMod, we must take care to convert it to a Local version first. Whenever we transfer a protobuf pointer to the engine, we must convert it to a Private handle. For platforms with no ABI differences (almost all of them), the handle is a no-op. The private and local localities are compatible and no translation takes place. On macOS, CS:GO does require translation. SourceMod loads a tiny shim library that contains a copy of the protobuf sources compiled against the game's ABI. It then provides serialization and deserialization methods. SourceMod must not interact with the game's protobuf objects without first going through this proxy library. Note that PbHandle is not quite like unique_ptr. It can be converted into a PbHandle that does not destroy the underlying object. This is mainly because UserMessages.cpp has rather complex state, so it is useful to track locality without destroying an object. An unowned PbHandle must not outlive the owning PbHandle.
This commit is contained in:
parent
d525b466ec
commit
e5ddbd9886
@ -553,25 +553,7 @@ class SMConfig(object):
|
||||
if builder.target.platform == 'linux':
|
||||
if sdk.name in ['csgo', 'blade']:
|
||||
compiler.linkflags.remove('-static-libstdc++')
|
||||
compiler.linkflags += ['-lstdc++']
|
||||
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
||||
elif builder.target.platform == 'mac':
|
||||
if sdk.name in ['csgo']:
|
||||
# Switch libc++ to libstdc++ for protobuf linkage.
|
||||
compiler.cxxflags.remove('-stdlib=libc++')
|
||||
compiler.linkflags.remove('-stdlib=libc++')
|
||||
compiler.linkflags.remove('-lc++')
|
||||
|
||||
compiler.cxxflags += ['-stdlib=libstdc++']
|
||||
compiler.linkflags += ['-stdlib=libstdc++']
|
||||
compiler.linkflags += ['-lstdc++']
|
||||
|
||||
if 'c++1y' in compiler.cxxflags:
|
||||
compiler.cxxflags.remove('-std=c++1y')
|
||||
compiler.cxxflags += ['-std=c++11']
|
||||
elif 'c++14' in compiler.cxxflags:
|
||||
compiler.cxxflags.remove('-std=c++14')
|
||||
compiler.cxxflags += ['-std=c++11']
|
||||
|
||||
for path in paths:
|
||||
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
||||
|
108
core/AMBuilder
108
core/AMBuilder
@ -4,42 +4,43 @@ import os
|
||||
project = SM.HL2Project(builder, 'sourcemod')
|
||||
|
||||
project.sources += [
|
||||
'MenuStyle_Valve.cpp',
|
||||
'logic_bridge.cpp',
|
||||
'smn_entities.cpp',
|
||||
'sm_stringutil.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'smn_events.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
'ChatTriggers.cpp',
|
||||
'smn_player.cpp',
|
||||
'sourcemod.cpp',
|
||||
'concmd_cleaner.cpp',
|
||||
'HalfLife2.cpp',
|
||||
'NextMap.cpp',
|
||||
'ConCmdManager.cpp',
|
||||
'ConVarManager.cpp',
|
||||
'ConsoleDetours.cpp',
|
||||
'CoreConfig.cpp',
|
||||
'EventManager.cpp',
|
||||
'GameHooks.cpp',
|
||||
'HalfLife2.cpp',
|
||||
'Logger.cpp',
|
||||
'MenuManager.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'MenuStyle_Valve.cpp',
|
||||
'MenuVoting.cpp',
|
||||
'NextMap.cpp',
|
||||
'PlayerManager.cpp',
|
||||
'TimerSys.cpp',
|
||||
'CoreConfig.cpp',
|
||||
'Logger.cpp',
|
||||
'smn_halflife.cpp',
|
||||
'smn_console.cpp',
|
||||
'UserMessages.cpp',
|
||||
'MenuManager.cpp',
|
||||
'smn_hudtext.cpp',
|
||||
'smn_usermsgs.cpp',
|
||||
'MenuStyle_Base.cpp',
|
||||
'smn_keyvalues.cpp',
|
||||
'smn_vector.cpp',
|
||||
'EventManager.cpp',
|
||||
'MenuStyle_Radio.cpp',
|
||||
'concmd_cleaner.cpp',
|
||||
'frame_hooks.cpp',
|
||||
'logic_bridge.cpp',
|
||||
'pb_handle.cpp',
|
||||
'sm_autonatives.cpp',
|
||||
'ConsoleDetours.cpp',
|
||||
'sm_stringutil.cpp',
|
||||
'smn_commandline.cpp',
|
||||
'GameHooks.cpp',
|
||||
'smn_console.cpp',
|
||||
'smn_entities.cpp',
|
||||
'smn_events.cpp',
|
||||
'smn_halflife.cpp',
|
||||
'smn_hudtext.cpp',
|
||||
'smn_keyvalues.cpp',
|
||||
'smn_nextmap.cpp',
|
||||
'smn_player.cpp',
|
||||
'smn_usermsgs.cpp',
|
||||
'smn_vector.cpp',
|
||||
'sourcemm_api.cpp',
|
||||
'sourcemod.cpp',
|
||||
]
|
||||
|
||||
for sdk_name in SM.sdks:
|
||||
@ -57,18 +58,20 @@ for sdk_name in SM.sdks:
|
||||
builder.sourcePath
|
||||
]
|
||||
|
||||
pb_includes = []
|
||||
if sdk.name == 'csgo':
|
||||
compiler.cxxincludes += [
|
||||
pb_includes = [
|
||||
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
|
||||
]
|
||||
elif sdk.name == 'blade':
|
||||
compiler.cxxincludes += [
|
||||
pb_includes = [
|
||||
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf')
|
||||
]
|
||||
compiler.cxxincludes += pb_includes
|
||||
|
||||
if compiler.like('msvc'):
|
||||
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
|
||||
@ -84,9 +87,9 @@ for sdk_name in SM.sdks:
|
||||
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
|
||||
elif builder.target.platform == 'mac':
|
||||
if arch == 'x86':
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf-libcxx.a')
|
||||
elif arch == 'x64':
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
|
||||
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf-libcxx.a')
|
||||
elif builder.target.platform == 'windows':
|
||||
msvc_ver = compiler.version
|
||||
vs_year = ''
|
||||
@ -111,18 +114,53 @@ for sdk_name in SM.sdks:
|
||||
'vprof_tool.cpp',
|
||||
]
|
||||
|
||||
pb_sources = []
|
||||
if sdk.name == 'csgo':
|
||||
binary.sources += [
|
||||
pb_sources = [
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
|
||||
]
|
||||
elif sdk.name == 'blade':
|
||||
binary.sources += [
|
||||
pb_sources = [
|
||||
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessages.pb.cc'),
|
||||
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessage_helpers.cpp'),
|
||||
]
|
||||
if len(pb_sources):
|
||||
binary.sources += pb_sources
|
||||
binary.compiler.cxxdefines += ['PROTOBUF_ENABLE']
|
||||
|
||||
if builder.target.platform == 'mac' and sdk.name in ['csgo']:
|
||||
# We need a proxy library since the game uses libstdc++.
|
||||
pb_binary = SM.HL2Library(builder, 'pbproxy.' + sdk.ext, sdk, arch)
|
||||
pb_binary.sources += pb_sources
|
||||
pb_binary.sources += ['pb_proxy.cpp']
|
||||
pb_binary.compiler.cxxincludes += pb_includes
|
||||
|
||||
# Switch from libc++ to libstdc++.
|
||||
pb_binary.compiler.cxxflags.remove('-stdlib=libc++')
|
||||
pb_binary.compiler.linkflags.remove('-lc++')
|
||||
pb_binary.compiler.linkflags.remove('-stdlib=libc++')
|
||||
pb_binary.compiler.cxxflags.append('-stdlib=libstdc++')
|
||||
pb_binary.compiler.linkflags.append('-lstdc++')
|
||||
pb_binary.compiler.linkflags.append('-stdlib=libstdc++')
|
||||
if '-std=c++1y' in pb_binary.compiler.cxxflags:
|
||||
pb_binary.compiler.cxxflags.remove('-std=c++1y')
|
||||
elif '-std=c++14' in pb_binary.compiler.cxxflags:
|
||||
pb_binary.compiler.cxxflags.remove('-std=c++14')
|
||||
|
||||
if arch == 'x86':
|
||||
pb_lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
|
||||
elif arch == 'x64':
|
||||
pb_lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
|
||||
pb_binary.compiler.linkflags.append(pb_lib_path)
|
||||
|
||||
SM.binaries += [builder.Add(pb_binary)]
|
||||
|
||||
binary.compiler.cxxdefines += [
|
||||
'PROTOBUF_PROXY_ENABLE',
|
||||
'PROTOBUF_PROXY_BINARY_NAME="pbproxy.{}"'.format(sdk.ext),
|
||||
]
|
||||
|
||||
SM.binaries += builder.Add(project)
|
||||
|
||||
|
@ -42,6 +42,10 @@
|
||||
|
||||
UserMessages g_UserMsgs;
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
const protobuf::Message *GetMessagePrototype(int msg_type);
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
|
||||
#else
|
||||
@ -58,7 +62,7 @@ UserMessages::UserMessages()
|
||||
: m_InterceptBuffer(m_pBase, 2500)
|
||||
{
|
||||
#else
|
||||
: m_InterceptBuffer(NULL)
|
||||
: m_InterceptBuffer(nullptr)
|
||||
{
|
||||
#endif
|
||||
m_HookCount = 0;
|
||||
@ -233,7 +237,7 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
|
||||
#ifndef USE_PROTOBUF_USERMESSAGES
|
||||
return NULL;
|
||||
#else
|
||||
protobuf::Message *buffer;
|
||||
PbHandle buffer;
|
||||
|
||||
if (m_InExec || m_InHook)
|
||||
{
|
||||
@ -262,8 +266,9 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
// direct message creation, return buffer "from engine". keep track
|
||||
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
|
||||
buffer = m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
buffer = m_FakeEngineBuffer.AsUnowned();
|
||||
} else {
|
||||
char messageName[32];
|
||||
if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
|
||||
@ -272,27 +277,30 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
// The message returned here should always local.
|
||||
auto msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
switch (m_FakeMetaRes)
|
||||
{
|
||||
case MRES_IGNORED:
|
||||
case MRES_HANDLED:
|
||||
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
|
||||
buffer = m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
buffer = m_FakeEngineBuffer.AsUnowned();
|
||||
break;
|
||||
|
||||
case MRES_OVERRIDE:
|
||||
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
// fallthrough
|
||||
case MRES_SUPERCEDE:
|
||||
buffer = msg;
|
||||
buffer = std::move(msg);
|
||||
break;
|
||||
}
|
||||
|
||||
OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
assert(!buffer.is_owned());
|
||||
return buffer.GetLocalMessage();
|
||||
#endif // USE_PROTOBUF_USERMESSAGES
|
||||
}
|
||||
|
||||
@ -306,9 +314,10 @@ bool UserMessages::EndMessage()
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
if (m_CurFlags & USERMSG_BLOCKHOOKS)
|
||||
{
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||
delete m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer = NULL;
|
||||
PbHandle priv = m_FakeEngineBuffer.ToPrivate(m_CurId);
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId,
|
||||
*priv.GetPrivateMessage());
|
||||
m_FakeEngineBuffer = nullptr;
|
||||
} else {
|
||||
OnMessageEnd_Pre();
|
||||
|
||||
@ -317,10 +326,13 @@ bool UserMessages::EndMessage()
|
||||
case MRES_IGNORED:
|
||||
case MRES_HANDLED:
|
||||
case MRES_OVERRIDE:
|
||||
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
|
||||
delete m_FakeEngineBuffer;
|
||||
m_FakeEngineBuffer = NULL;
|
||||
{
|
||||
PbHandle priv = m_FakeEngineBuffer.ToPrivate(m_CurId);
|
||||
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId,
|
||||
*priv.GetPrivateMessage());
|
||||
m_FakeEngineBuffer = nullptr;
|
||||
break;
|
||||
}
|
||||
//case MRES_SUPERCEDE:
|
||||
}
|
||||
|
||||
@ -440,7 +452,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
|
||||
}
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
|
||||
const protobuf::Message *GetMessagePrototype(int msg_type)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
|
||||
@ -527,7 +539,8 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
|
||||
m_FakeEngineBuffer =
|
||||
PbHandle(&const_cast<protobuf::Message &>(msg), PbHandle::Unowned, PbHandle::Private);
|
||||
}
|
||||
|
||||
OnStartMessage_Post(&filter, msg_type, pszName);
|
||||
@ -563,7 +576,7 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
PbHandle UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#else
|
||||
@ -577,7 +590,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
||||
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
|
||||
{
|
||||
m_InHook = false;
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, nullptr);
|
||||
}
|
||||
|
||||
m_CurId = msg_type;
|
||||
@ -588,22 +601,20 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|
||||
if (!is_intercept_empty)
|
||||
{
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
if (m_InterceptBuffer)
|
||||
delete m_InterceptBuffer;
|
||||
m_InterceptBuffer = GetMessagePrototype(msg_type)->New();
|
||||
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
|
||||
m_InterceptBuffer =
|
||||
PbHandle(GetMessagePrototype(msg_type)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer.AsUnowned());
|
||||
#else
|
||||
m_InterceptBuffer.Reset();
|
||||
UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
|
||||
UM_RETURN_META_VALUE(MRES_IGNORED, nullptr);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
void* UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
|
||||
#else
|
||||
@ -617,9 +628,9 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
if (m_FakeMetaRes == MRES_SUPERCEDE)
|
||||
m_OrigBuffer = m_InterceptBuffer;
|
||||
m_OrigBuffer = m_InterceptBuffer.AsUnowned();
|
||||
else
|
||||
m_OrigBuffer = m_FakeEngineBuffer;
|
||||
m_OrigBuffer = m_FakeEngineBuffer.AsUnowned();
|
||||
#else
|
||||
m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
|
||||
#endif
|
||||
@ -715,8 +726,11 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
{
|
||||
pInfo = (*iter);
|
||||
pInfo->IsHooked = true;
|
||||
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
|
||||
PbHandle local = m_InterceptBuffer.ToLocal(m_CurId);
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, local.GetLocalMessage(), m_CurRecFilter);
|
||||
m_InterceptBuffer.CopyFrom(local);
|
||||
#else
|
||||
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
|
||||
#endif
|
||||
@ -768,7 +782,8 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
if (!handled && intercepted)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
|
||||
PbHandle priv = m_InterceptBuffer.ToPrivate(m_CurId);
|
||||
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *priv.GetPrivateMessage());
|
||||
#else
|
||||
bf_write *engine_bfw;
|
||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
@ -784,12 +799,9 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
int size = m_OrigBuffer->ByteSize();
|
||||
uint8 *data = (uint8 *)stackalloc(size);
|
||||
m_OrigBuffer->SerializePartialToArray(data, size);
|
||||
|
||||
protobuf::Message *pTempMsg = GetMessagePrototype(m_CurId)->New();
|
||||
pTempMsg->ParsePartialFromArray(data, size);
|
||||
PbHandle tmp_msg(GetMessagePrototype(m_CurId)->New(), PbHandle::Owned, PbHandle::Local);
|
||||
tmp_msg.CopyFrom(m_OrigBuffer);
|
||||
auto pTempMsg = tmp_msg.GetLocalMessage();
|
||||
#else
|
||||
bf_write *pTempMsg = m_OrigBuffer;
|
||||
#endif
|
||||
@ -812,10 +824,6 @@ void UserMessages::OnMessageEnd_Pre()
|
||||
pInfo->IsHooked = false;
|
||||
iter++;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
delete pTempMsg;
|
||||
#endif
|
||||
}
|
||||
|
||||
UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
|
||||
|
@ -52,6 +52,7 @@ using namespace SourceMod;
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <netmessages.pb.h>
|
||||
#include "pb_handle.h"
|
||||
|
||||
using namespace google;
|
||||
#else
|
||||
@ -108,8 +109,8 @@ public:
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|
||||
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
PbHandle OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
void* OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
|
||||
@ -121,7 +122,6 @@ public:
|
||||
void OnMessageEnd_Post();
|
||||
private:
|
||||
#ifdef USE_PROTOBUF_USERMESSAGES
|
||||
const protobuf::Message *GetMessagePrototype(int msg_type);
|
||||
bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
|
||||
#else
|
||||
@ -141,11 +141,11 @@ private:
|
||||
bf_read m_ReadBuffer;
|
||||
#else
|
||||
// The engine used to provide this. Now we track it.
|
||||
protobuf::Message *m_OrigBuffer;
|
||||
protobuf::Message *m_FakeEngineBuffer;
|
||||
PbHandle m_OrigBuffer;
|
||||
PbHandle m_FakeEngineBuffer;
|
||||
META_RES m_FakeMetaRes;
|
||||
|
||||
protobuf::Message *m_InterceptBuffer;
|
||||
PbHandle m_InterceptBuffer;
|
||||
#endif
|
||||
size_t m_HookCount;
|
||||
bool m_InHook;
|
||||
|
@ -51,6 +51,9 @@
|
||||
#include <bridge/include/IVEngineServerBridge.h>
|
||||
#include <bridge/include/IPlayerInfoBridge.h>
|
||||
#include <bridge/include/IFileSystemBridge.h>
|
||||
#if PROTOBUF_PROXY_ENABLE
|
||||
# include "pb_handle.h"
|
||||
#endif
|
||||
|
||||
sm_logic_t logicore;
|
||||
|
||||
@ -653,6 +656,41 @@ void CoreProviderImpl::InitializeBridge()
|
||||
rootmenu = logicore.rootmenu;
|
||||
}
|
||||
|
||||
bool CoreProviderImpl::LoadProtobufProxy(char *error, size_t maxlength)
|
||||
{
|
||||
#if !defined(PROTOBUF_PROXY_ENABLE)
|
||||
return false;
|
||||
#else
|
||||
char file[PLATFORM_MAX_PATH];
|
||||
|
||||
#if !defined(PROTOBUF_PROXY_BINARY_NAME)
|
||||
# error "No engine suffix defined"
|
||||
#endif
|
||||
|
||||
/* Now it's time to load the logic binary */
|
||||
g_SMAPI->PathFormat(file,
|
||||
sizeof(file),
|
||||
"%s/bin/" PLATFORM_ARCH_FOLDER PROTOBUF_PROXY_BINARY_NAME PLATFORM_LIB_EXT,
|
||||
g_SourceMod.GetSourceModPath());
|
||||
|
||||
char myerror[255];
|
||||
pbproxy_ = ke::SharedLib::Open(file, myerror, sizeof(myerror));
|
||||
if (!pbproxy_) {
|
||||
ke::SafeSprintf(error, maxlength, "failed to load %s: %s", file, myerror);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto fn = pbproxy_->get<GetProtobufProxyFn>("GetProtobufProxy");
|
||||
if (!fn) {
|
||||
ke::SafeStrcpy(error, maxlength, "could not find GetProtobufProxy function");
|
||||
return false;
|
||||
}
|
||||
|
||||
gProtobufProxy = fn();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CoreProviderImpl::LoadBridge(char *error, size_t maxlength)
|
||||
{
|
||||
char file[PLATFORM_MAX_PATH];
|
||||
|
35
core/pb_handle.cpp
Normal file
35
core/pb_handle.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2020 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#include "pb_handle.h"
|
||||
|
||||
#if defined PROTOBUF_PROXY_ENABLE
|
||||
IProtobufProxy* gProtobufProxy = nullptr;
|
||||
#endif
|
216
core/pb_handle.h
Normal file
216
core/pb_handle.h
Normal file
@ -0,0 +1,216 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2020 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined(PROTOBUF_ENABLE)
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
# include "pb_proxy.h"
|
||||
|
||||
extern IProtobufProxy* gProtobufProxy;
|
||||
#endif
|
||||
|
||||
const google::protobuf::Message *GetMessagePrototype(int msg_type);
|
||||
|
||||
// On SDKs which use protobufs, the engine has objects compiled against a specific
|
||||
// version of protobuf. Normally this is fine, we take care on Linux to use the
|
||||
// same C++ ABI. On macOS however, we use libc++ to enable C++11 functionality,
|
||||
// whereas the protobuf library has been compiled with libstc++. These ABIs are
|
||||
// not compatible.
|
||||
//
|
||||
// To address the problem, we introduce PbHandle. PbHandle is a wrapper around
|
||||
// protobuf::Message with two added pieces of state: whether or not the handle
|
||||
// "owns" the message (and can free it in its destructor), and whether or not
|
||||
// the handle was created by the engine (private) or created by SourceMod
|
||||
// (local).
|
||||
//
|
||||
// Whenever we transfer a protobuf::Message pointer to SourceMod, we must take
|
||||
// care to convert it to a Local version first. Whenever we transfer a protobuf
|
||||
// pointer to the engine, we must convert it to a Private handle.
|
||||
//
|
||||
// For platforms with no ABI differences (almost all of them), the handle is a
|
||||
// no-op. The private and local localities are compatible and no translation
|
||||
// takes place.
|
||||
//
|
||||
// On macOS, CS:GO does require translation. SourceMod loads a tiny shim
|
||||
// library that contains a copy of the protobuf sources compiled against the
|
||||
// game's ABI. It then provides serialization and deserialization methods.
|
||||
// SourceMod must not interact with the game's protobuf objects without first
|
||||
// going through this proxy library.
|
||||
//
|
||||
// Note that PbHandle is not quite like unique_ptr_. It can be converted into a
|
||||
// PbHandle that does not destroy the underlying object. This is mainly because
|
||||
// UserMessages.cpp has rather complex state, so it is useful to track locality
|
||||
// without destroying an object. An unowned PbHandle must not outlive the
|
||||
// owning PbHandle.
|
||||
class PbHandle
|
||||
{
|
||||
public:
|
||||
enum Ownership {
|
||||
Owned,
|
||||
Unowned,
|
||||
};
|
||||
enum Locality {
|
||||
Local,
|
||||
Private,
|
||||
};
|
||||
|
||||
PbHandle() : msg_(nullptr) {}
|
||||
PbHandle(decltype(nullptr)) : msg_(nullptr) {}
|
||||
PbHandle(google::protobuf::Message* msg, Ownership ownership, Locality locality)
|
||||
: msg_(msg),
|
||||
ownership_(ownership),
|
||||
locality_(locality)
|
||||
{}
|
||||
PbHandle(PbHandle&& other)
|
||||
: msg_(other.msg_),
|
||||
ownership_(other.ownership_),
|
||||
locality_(other.locality_)
|
||||
{
|
||||
other.msg_ = nullptr;
|
||||
}
|
||||
PbHandle(const PbHandle&) = delete;
|
||||
|
||||
~PbHandle() {
|
||||
maybe_free();
|
||||
}
|
||||
|
||||
PbHandle& operator =(PbHandle&& other) {
|
||||
maybe_free();
|
||||
msg_ = other.msg_;
|
||||
ownership_ = other.ownership_;
|
||||
locality_ = other.locality_;
|
||||
other.msg_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
PbHandle& operator =(const PbHandle&) = delete;
|
||||
|
||||
google::protobuf::Message* operator ->() const { return msg_; }
|
||||
|
||||
google::protobuf::Message* GetLocalMessage() {
|
||||
assert(locality_ == Local);
|
||||
return msg_;
|
||||
}
|
||||
google::protobuf::Message* GetPrivateMessage() {
|
||||
assert(locality_ == Private);
|
||||
return msg_;
|
||||
}
|
||||
|
||||
PbHandle ToLocal(int msg_type) {
|
||||
if (locality_ == Local)
|
||||
return AsUnowned();
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
PbHandle local(GetMessagePrototype(msg_type)->New(), Owned, Local);
|
||||
local.CopyFromPrivate(msg_);
|
||||
return local;
|
||||
#else
|
||||
return PbHandle(msg_, Unowned, Local);
|
||||
#endif
|
||||
}
|
||||
|
||||
PbHandle ToPrivate(int msg_type) {
|
||||
if (locality_ == Private)
|
||||
return AsUnowned();
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
PbHandle priv(gProtobufProxy->NewPrototype(msg_type), Owned, Private);
|
||||
priv.CopyFromLocal(msg_);
|
||||
return priv;
|
||||
#else
|
||||
return PbHandle(msg_, Unowned, Private);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CopyFrom(const PbHandle& other) {
|
||||
if (other.msg_ == msg_) {
|
||||
assert(other.locality_ == locality_);
|
||||
return;
|
||||
}
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
if (other.locality_ == Local)
|
||||
CopyFromLocal(other.msg_);
|
||||
else if (other.locality_ == Private)
|
||||
CopyFromPrivate(other.msg_);
|
||||
#else
|
||||
msg_->CopyFrom(*other.msg_);
|
||||
#endif
|
||||
}
|
||||
|
||||
PbHandle AsUnowned() {
|
||||
return PbHandle(msg_, Unowned, locality_);
|
||||
}
|
||||
|
||||
bool is_owned() const { return ownership_ == Owned; }
|
||||
bool is_local() const { return locality_ == Local; }
|
||||
|
||||
private:
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
void CopyFromPrivate(google::protobuf::Message* message) {
|
||||
void* out;
|
||||
size_t len;
|
||||
if (!gProtobufProxy->Serialize(message, &out, &len))
|
||||
return;
|
||||
if (locality_ == Local)
|
||||
msg_->ParsePartialFromArray(out, len);
|
||||
else
|
||||
gProtobufProxy->Deserialize(out, len, msg_);
|
||||
gProtobufProxy->FreeBuffer(out);
|
||||
}
|
||||
|
||||
void CopyFromLocal(google::protobuf::Message* message) {
|
||||
if (locality_ == Local) {
|
||||
msg_->CopyFrom(*message);
|
||||
} else {
|
||||
auto data = message->SerializePartialAsString();
|
||||
gProtobufProxy->Deserialize(data.data(), data.size(), msg_);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void maybe_free() {
|
||||
if (ownership_ != Owned)
|
||||
return;
|
||||
#if defined(PROTOBUF_PROXY_ENABLE)
|
||||
if (locality_ == Private) {
|
||||
gProtobufProxy->FreeMessage(msg_);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
delete msg_;
|
||||
}
|
||||
|
||||
private:
|
||||
google::protobuf::Message* msg_ = nullptr;
|
||||
Ownership ownership_ = Unowned;
|
||||
Locality locality_ = Local;
|
||||
};
|
||||
|
||||
#endif // PROTOBUF_ENABLE
|
100
core/pb_proxy.cpp
Normal file
100
core/pb_proxy.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2020 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#include "pb_proxy.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sm_platform.h>
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
# include <cstrike15_usermessage_helpers.h>
|
||||
#else
|
||||
# error "No source engine compatibility"
|
||||
#endif
|
||||
|
||||
class ProtobufProxy : public IProtobufProxy
|
||||
{
|
||||
public:
|
||||
bool Serialize(const google::protobuf::Message* message, void** out, size_t* len);
|
||||
void FreeBuffer(void* data);
|
||||
bool Deserialize(const void* buffer, size_t len, google::protobuf::Message* message);
|
||||
google::protobuf::Message* NewPrototype(int msg_type);
|
||||
void FreeMessage(google::protobuf::Message* message);
|
||||
};
|
||||
|
||||
static ProtobufProxy sProtobufProxy;
|
||||
|
||||
PLATFORM_EXTERN_C IProtobufProxy*
|
||||
GetProtobufProxy()
|
||||
{
|
||||
return &sProtobufProxy;
|
||||
}
|
||||
|
||||
bool
|
||||
ProtobufProxy::Serialize(const google::protobuf::Message* message, void** out, size_t* len)
|
||||
{
|
||||
*len = message->ByteSize();
|
||||
*out = malloc(*len);
|
||||
if (!*out)
|
||||
return false;
|
||||
if (!message->SerializePartialToArray(*out, *len)) {
|
||||
free(*out);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ProtobufProxy::FreeBuffer(void* data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
bool
|
||||
ProtobufProxy::Deserialize(const void* buffer, size_t len, google::protobuf::Message* message)
|
||||
{
|
||||
return message->ParsePartialFromArray(buffer, len);
|
||||
}
|
||||
|
||||
google::protobuf::Message*
|
||||
ProtobufProxy::NewPrototype(int msg_type)
|
||||
{
|
||||
#if SOURCE_ENGINE == SE_CSGO
|
||||
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
|
||||
#else
|
||||
# error "No source engine compatibility."
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ProtobufProxy::FreeMessage(google::protobuf::Message* message)
|
||||
{
|
||||
delete message;
|
||||
}
|
58
core/pb_proxy.h
Normal file
58
core/pb_proxy.h
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* vim: set ts=4 sw=4 tw=99 noet :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2020 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
class IProtobufProxy
|
||||
{
|
||||
public:
|
||||
// Serialize the given message into a buffer. The buffer and its length are placed in |out|.
|
||||
// The buffer must be freed with FreeBuffer.
|
||||
virtual bool Serialize(const google::protobuf::Message* message, void** out, size_t* len) = 0;
|
||||
virtual void FreeBuffer(void* data) = 0;
|
||||
|
||||
// Deserialize the given buffer into a message.
|
||||
virtual bool Deserialize(const void* buffer, size_t len, google::protobuf::Message* message) = 0;
|
||||
|
||||
// Allocate/free a prototype.
|
||||
virtual google::protobuf::Message* NewPrototype(int msg_type) = 0;
|
||||
virtual void FreeMessage(google::protobuf::Message* message) = 0;
|
||||
|
||||
bool Serialize(const google::protobuf::Message& message, void** out, size_t* len) {
|
||||
return Serialize(&message, out, len);
|
||||
}
|
||||
bool Deserialize(const void* buffer, size_t len, google::protobuf::Message& message) {
|
||||
return Deserialize(buffer, len, &message);
|
||||
}
|
||||
};
|
||||
|
||||
typedef IProtobufProxy*(*GetProtobufProxyFn)();
|
@ -38,6 +38,7 @@ public:
|
||||
|
||||
// Local functions.
|
||||
void InitializeBridge();
|
||||
bool LoadProtobufProxy(char *error, size_t maxlength);
|
||||
bool LoadBridge(char *error, size_t maxlength);
|
||||
void ShutdownBridge();
|
||||
|
||||
@ -75,6 +76,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
ke::RefPtr<ke::SharedLib> pbproxy_;
|
||||
ke::RefPtr<ke::SharedLib> logic_;
|
||||
LogicInitFunction logic_init_;
|
||||
GameHooks hooks_;
|
||||
|
Loading…
Reference in New Issue
Block a user