mirror of
https://github.com/asherkin/accelerator.git
synced 2025-12-07 02:18:29 +00:00
Refactor API
Forward notifies plugins when the extension is done uploading. Plugins can fetch data from uploaded crashes via natives. Added example plugin.
This commit is contained in:
parent
d0cb652e0d
commit
1a6223ad82
@ -10,6 +10,7 @@ folder_list = [
|
|||||||
'addons/sourcemod/extensions',
|
'addons/sourcemod/extensions',
|
||||||
'addons/sourcemod/gamedata',
|
'addons/sourcemod/gamedata',
|
||||||
'addons/sourcemod/configs',
|
'addons/sourcemod/configs',
|
||||||
|
'addons/sourcemod/scripting',
|
||||||
'addons/sourcemod/scripting/include',
|
'addons/sourcemod/scripting/include',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -44,12 +45,19 @@ def CopyDirContent(src, dest):
|
|||||||
builder.AddCopy(item.path, dest_entry)
|
builder.AddCopy(item.path, dest_entry)
|
||||||
|
|
||||||
# Include files
|
# Include files
|
||||||
CopyFiles('scripting', 'addons/sourcemod/scripting/include',
|
CopyFiles('scripting/include', 'addons/sourcemod/scripting/include',
|
||||||
[
|
[
|
||||||
'accelerator.inc',
|
'accelerator.inc',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Example files
|
||||||
|
CopyFiles('scripting', 'addons/sourcemod/scripting',
|
||||||
|
[
|
||||||
|
'accelerator_example.sp',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# Copy binaries.
|
# Copy binaries.
|
||||||
for task in Accelerator.extension:
|
for task in Accelerator.extension:
|
||||||
if task.target.arch == 'x86_64':
|
if task.target.arch == 'x86_64':
|
||||||
|
|||||||
@ -8,6 +8,7 @@ project.sources = [
|
|||||||
'extension.cpp',
|
'extension.cpp',
|
||||||
'MemoryDownloader.cpp',
|
'MemoryDownloader.cpp',
|
||||||
'forwards.cpp',
|
'forwards.cpp',
|
||||||
|
'natives.cpp',
|
||||||
os.path.join(Accelerator.sm_root, 'public', 'smsdk_ext.cpp')
|
os.path.join(Accelerator.sm_root, 'public', 'smsdk_ext.cpp')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
#include <IWebternet.h>
|
#include <IWebternet.h>
|
||||||
#include "MemoryDownloader.h"
|
#include "MemoryDownloader.h"
|
||||||
#include "forwards.h"
|
#include "forwards.h"
|
||||||
|
#include "natives.h"
|
||||||
|
|
||||||
#if defined _LINUX
|
#if defined _LINUX
|
||||||
#include "client/linux/handler/exception_handler.h"
|
#include "client/linux/handler/exception_handler.h"
|
||||||
@ -465,7 +466,8 @@ class UploadThread: public IThread
|
|||||||
count++;
|
count++;
|
||||||
g_pSM->LogError(myself, "Accelerator uploaded crash dump: %s", response);
|
g_pSM->LogError(myself, "Accelerator uploaded crash dump: %s", response);
|
||||||
if (log) fprintf(log, "Uploaded crash dump: %s\n", response);
|
if (log) fprintf(log, "Uploaded crash dump: %s\n", response);
|
||||||
extforwards::CallForward(count, response);
|
UploadedCrash crash{ response };
|
||||||
|
g_accelerator.StoreUploadedCrash(crash);
|
||||||
} else {
|
} else {
|
||||||
failed++;
|
failed++;
|
||||||
g_pSM->LogError(myself, "Accelerator failed to upload crash dump: %s", response);
|
g_pSM->LogError(myself, "Accelerator failed to upload crash dump: %s", response);
|
||||||
@ -497,6 +499,7 @@ class UploadThread: public IThread
|
|||||||
log = nullptr;
|
log = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_accelerator.MarkAsDoneUploading();
|
||||||
rootconsole->ConsolePrint("Accelerator upload thread finished. (%d skipped, %d uploaded, %d failed)", skip, count, failed);
|
rootconsole->ConsolePrint("Accelerator upload thread finished. (%d skipped, %d uploaded, %d failed)", skip, count, failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,6 +1085,25 @@ class UploadThread: public IThread
|
|||||||
}
|
}
|
||||||
} uploadThread;
|
} uploadThread;
|
||||||
|
|
||||||
|
class SourcePawnNotifyThread : public IThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void RunThread(IThreadHandle* pHandle) {
|
||||||
|
for (;;) {
|
||||||
|
// Wait until OnMapStart is called once, this should be enough delay to make sure plugins are loaded.
|
||||||
|
if (g_accelerator.IsMapStarted() && g_accelerator.IsDoneUploading()) {
|
||||||
|
extforwards::CallOnDoneUploadingForward();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTerminate(IThreadHandle* pHandle, bool cancel) {
|
||||||
|
}
|
||||||
|
|
||||||
|
} spNotifyThread;
|
||||||
|
|
||||||
class VFuncEmptyClass {};
|
class VFuncEmptyClass {};
|
||||||
|
|
||||||
const char *GetCmdLine()
|
const char *GetCmdLine()
|
||||||
@ -1119,6 +1141,11 @@ const char *GetCmdLine()
|
|||||||
return (const char *)(reinterpret_cast<VFuncEmptyClass*>(cmdline)->*u.mfpnew)();
|
return (const char *)(reinterpret_cast<VFuncEmptyClass*>(cmdline)->*u.mfpnew)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Accelerator::Accelerator() :
|
||||||
|
m_doneuploading(false), m_maphasstarted(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||||
{
|
{
|
||||||
sharesys->AddDependency(myself, "webternet.ext", true, true);
|
sharesys->AddDependency(myself, "webternet.ext", true, true);
|
||||||
@ -1144,6 +1171,7 @@ bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
|||||||
strncpy(crashGameDirectory, g_pSM->GetGameFolderName(), sizeof(crashGameDirectory) - 1);
|
strncpy(crashGameDirectory, g_pSM->GetGameFolderName(), sizeof(crashGameDirectory) - 1);
|
||||||
|
|
||||||
threader->MakeThread(&uploadThread);
|
threader->MakeThread(&uploadThread);
|
||||||
|
threader->MakeThread(&spNotifyThread); // This thread waits for accelator to be done uploading and for the first OnMapStart call, then fires a SourceMod forward
|
||||||
|
|
||||||
do {
|
do {
|
||||||
char gameconfigError[256];
|
char gameconfigError[256];
|
||||||
@ -1343,11 +1371,17 @@ void Accelerator::SDK_OnAllLoaded()
|
|||||||
{
|
{
|
||||||
extforwards::Init();
|
extforwards::Init();
|
||||||
sharesys->RegisterLibrary(myself, "accelerator");
|
sharesys->RegisterLibrary(myself, "accelerator");
|
||||||
|
|
||||||
|
natives::SetupNatives(m_natives);
|
||||||
|
m_natives.push_back({ nullptr, nullptr }); // SM requires this to signal the end of the native info array
|
||||||
|
|
||||||
|
sharesys->AddNatives(myself, m_natives.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Accelerator::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
|
void Accelerator::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
|
||||||
{
|
{
|
||||||
strncpy(crashMap, gamehelpers->GetCurrentMap(), sizeof(crashMap) - 1);
|
strncpy(crashMap, gamehelpers->GetCurrentMap(), sizeof(crashMap) - 1);
|
||||||
|
m_maphasstarted.store(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 010 Editor Template
|
/* 010 Editor Template
|
||||||
@ -1508,3 +1542,25 @@ void Accelerator::OnPluginUnloaded(IPlugin *plugin)
|
|||||||
|
|
||||||
SerializePluginContexts();
|
SerializePluginContexts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Accelerator::StoreUploadedCrash(UploadedCrash& crash)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_uploadedcrashes_mutex);
|
||||||
|
m_uploadedcrashes.push_back(std::move(crash));
|
||||||
|
}
|
||||||
|
|
||||||
|
const UploadedCrash* Accelerator::GetUploadedCrash(int element) const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_uploadedcrashes_mutex);
|
||||||
|
if (element < 0 || element >= static_cast<int>(m_uploadedcrashes.size())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &m_uploadedcrashes[element];
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_t Accelerator::GetUploadedCrashCount() const
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_uploadedcrashes_mutex);
|
||||||
|
return static_cast<cell_t>(m_uploadedcrashes.size());
|
||||||
|
}
|
||||||
|
|||||||
@ -26,14 +26,36 @@
|
|||||||
* @brief Accelerator extension code header.
|
* @brief Accelerator extension code header.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
#include "smsdk_ext.h"
|
#include "smsdk_ext.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Represents a crash that has been successfully uploaded to Accelerator's backend
|
||||||
|
*/
|
||||||
|
class UploadedCrash
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UploadedCrash(const char* response) :
|
||||||
|
m_httpresponse(response)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& GetHTTPResponse() const { return m_httpresponse; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_httpresponse; // HTTP response from the crash upload in free form text.
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sample implementation of the SDK Extension.
|
* @brief Sample implementation of the SDK Extension.
|
||||||
*/
|
*/
|
||||||
class Accelerator : public SDKExtension, IPluginsListener
|
class Accelerator : public SDKExtension, IPluginsListener
|
||||||
{
|
{
|
||||||
public: // SDKExtension
|
public: // SDKExtension
|
||||||
|
Accelerator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This is called after the initial loading sequence has been processed.
|
* @brief This is called after the initial loading sequence has been processed.
|
||||||
*
|
*
|
||||||
@ -73,6 +95,47 @@ public: // IPluginsListener
|
|||||||
* @brief Called when a plugin is unloaded (only if fully loaded).
|
* @brief Called when a plugin is unloaded (only if fully loaded).
|
||||||
*/
|
*/
|
||||||
virtual void OnPluginUnloaded(IPlugin *plugin);
|
virtual void OnPluginUnloaded(IPlugin *plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stores an uploaded crash into the vector.
|
||||||
|
* @param crash Uploaded crash instance to store.
|
||||||
|
*/
|
||||||
|
void StoreUploadedCrash(UploadedCrash& crash);
|
||||||
|
/**
|
||||||
|
* @brief Retrieves an uploaded crash from the given element.
|
||||||
|
* @param element Vector element (index) to read.
|
||||||
|
* @return Upload crash if found or NULL if out of bounds.
|
||||||
|
*/
|
||||||
|
const UploadedCrash* GetUploadedCrash(int element) const;
|
||||||
|
/**
|
||||||
|
* @brief Returns the number of uploaded crashes (for SourcePawn plugins).
|
||||||
|
* @return Number of uploaded crashes.
|
||||||
|
*/
|
||||||
|
cell_t GetUploadedCrashCount() const;
|
||||||
|
/**
|
||||||
|
* @brief Signals the extension that uploading is done.
|
||||||
|
*/
|
||||||
|
void MarkAsDoneUploading() { m_doneuploading.store(true); }
|
||||||
|
/**
|
||||||
|
* @brief Is Accelerator done uploading crashes.
|
||||||
|
* @return Returns true if yes, false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsDoneUploading() const { return m_doneuploading.load(); }
|
||||||
|
/**
|
||||||
|
* @brief Has the 'OnMapStart' function called at least once.
|
||||||
|
* @return True if yes, false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsMapStarted() const { return m_maphasstarted.load(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<UploadedCrash> m_uploadedcrashes; // Vector of uploaded crashes
|
||||||
|
std::vector<sp_nativeinfo_t> m_natives; // Vector of SourcePawn natives
|
||||||
|
mutable std::mutex m_uploadedcrashes_mutex; // mutex for accessing the m_uploadedcrashes vector
|
||||||
|
std::atomic_bool m_doneuploading; // Signals that Accelerator is done uploading crashes.
|
||||||
|
std::atomic_bool m_maphasstarted; // Signals that OnMapStart has been called at least once.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Expose the extension singleton.
|
||||||
|
extern Accelerator g_accelerator;
|
||||||
|
|
||||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||||
|
|||||||
@ -3,57 +3,32 @@
|
|||||||
#include "extension.h"
|
#include "extension.h"
|
||||||
#include "forwards.h"
|
#include "forwards.h"
|
||||||
|
|
||||||
static SourceMod::IForward* s_postuploadfoward = nullptr;
|
|
||||||
|
|
||||||
struct CrashPawnData
|
static SourceMod::IForward* s_ondoneuploadingforward = nullptr;
|
||||||
{
|
|
||||||
int index;
|
|
||||||
std::string response;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void OnCrashUploadedCallback(void* data)
|
static void OnDoneUploadingCallback(void* data)
|
||||||
{
|
{
|
||||||
CrashPawnData* crashdata = reinterpret_cast<CrashPawnData*>(data);
|
if (s_ondoneuploadingforward) {
|
||||||
|
s_ondoneuploadingforward->Execute();
|
||||||
if (s_postuploadfoward)
|
|
||||||
{
|
|
||||||
s_postuploadfoward->PushCell(crashdata->index);
|
|
||||||
s_postuploadfoward->PushString(crashdata->response.c_str());
|
|
||||||
s_postuploadfoward->PushCell(static_cast<cell_t>(crashdata->response.size()));
|
|
||||||
s_postuploadfoward->Execute(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete crashdata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void extforwards::Init()
|
void extforwards::Init()
|
||||||
{
|
{
|
||||||
std::array types = {
|
s_ondoneuploadingforward = forwards->CreateForward("Accelerator_OnDoneUploadingCrashes", SourceMod::ExecType::ET_Ignore, 0, nullptr);
|
||||||
SourceMod::ParamType::Param_Cell,
|
|
||||||
SourceMod::ParamType::Param_String,
|
|
||||||
SourceMod::ParamType::Param_Cell,
|
|
||||||
};
|
|
||||||
|
|
||||||
s_postuploadfoward = forwards->CreateForward("Accelerator_OnCrashUploaded", SourceMod::ExecType::ET_Ignore, 3, types.data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void extforwards::Shutdown()
|
void extforwards::Shutdown()
|
||||||
{
|
{
|
||||||
if (s_postuploadfoward)
|
if (s_ondoneuploadingforward) {
|
||||||
{
|
forwards->ReleaseForward(s_ondoneuploadingforward);
|
||||||
forwards->ReleaseForward(s_postuploadfoward);
|
s_ondoneuploadingforward = nullptr;
|
||||||
s_postuploadfoward = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void extforwards::CallForward(int crashIndex, const char* response)
|
void extforwards::CallOnDoneUploadingForward()
|
||||||
{
|
{
|
||||||
CrashPawnData* data = new CrashPawnData;
|
smutils->AddFrameAction(OnDoneUploadingCallback, nullptr);
|
||||||
|
|
||||||
data->index = crashIndex;
|
|
||||||
data->response.assign(response);
|
|
||||||
|
|
||||||
// Accelerator uploads from a secondary thread, calling a forward directly will crash
|
|
||||||
// this will call the forward from the main thread.
|
|
||||||
smutils->AddFrameAction(OnCrashUploadedCallback, reinterpret_cast<void*>(data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,13 @@
|
|||||||
|
|
||||||
namespace extforwards
|
namespace extforwards
|
||||||
{
|
{
|
||||||
|
// Initialize the sourcepawn forwards.
|
||||||
void Init();
|
void Init();
|
||||||
|
// Shutdown the sourcepawn forwards.
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void CallForward(int crashIndex, const char* response);
|
void CallOnDoneUploadingForward();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // !_INCLUDE_FORWARDS_H_
|
#endif // !_INCLUDE_FORWARDS_H_
|
||||||
|
|||||||
54
extension/natives.cpp
Normal file
54
extension/natives.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <amtl/am-string.h>
|
||||||
|
#include "extension.h"
|
||||||
|
#include "natives.h"
|
||||||
|
|
||||||
|
static cell_t Native_GetUploadedCrashCount(IPluginContext* context, const cell_t* params)
|
||||||
|
{
|
||||||
|
return g_accelerator.GetUploadedCrashCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t Native_IsDoneUploadingCrashes(IPluginContext* context, const cell_t* params)
|
||||||
|
{
|
||||||
|
if (g_accelerator.IsDoneUploading()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t Native_GetCrashHTTPResponse(IPluginContext* context, const cell_t* params)
|
||||||
|
{
|
||||||
|
if (!g_accelerator.IsDoneUploading()) {
|
||||||
|
context->ReportError("Wait until accelerator is done uploading crashes before accessing crash information!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int element = static_cast<int>(params[1]);
|
||||||
|
const UploadedCrash* crash = g_accelerator.GetUploadedCrash(element);
|
||||||
|
|
||||||
|
if (!crash) {
|
||||||
|
context->ReportError("Crash index %i is invalid!", element);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* buffer;
|
||||||
|
context->LocalToString(params[2], &buffer);
|
||||||
|
|
||||||
|
size_t maxsize = static_cast<size_t>(params[3]);
|
||||||
|
|
||||||
|
ke::SafeStrcpy(buffer, maxsize, crash->GetHTTPResponse().c_str());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void natives::SetupNatives(std::vector<sp_nativeinfo_t>& vec)
|
||||||
|
{
|
||||||
|
sp_nativeinfo_t list[] = {
|
||||||
|
{"Accelerator_GetUploadedCrashCount", Native_GetUploadedCrashCount},
|
||||||
|
{"Accelerator_IsDoneUploadingCrashes", Native_IsDoneUploadingCrashes},
|
||||||
|
{"Accelerator_GetCrashHTTPResponse", Native_GetCrashHTTPResponse},
|
||||||
|
};
|
||||||
|
|
||||||
|
vec.insert(vec.end(), std::begin(list), std::end(list));
|
||||||
|
}
|
||||||
10
extension/natives.h
Normal file
10
extension/natives.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef _INCLUDE_NATIVES_H_
|
||||||
|
#define _INCLUDE_NATIVES_H_
|
||||||
|
|
||||||
|
|
||||||
|
namespace natives
|
||||||
|
{
|
||||||
|
void SetupNatives(std::vector<sp_nativeinfo_t>& vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !_INCLUDE_NATIVES_H_
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/**
|
|
||||||
* Accelerator's SourcePawn include file
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined _accelerator_included
|
|
||||||
#endinput
|
|
||||||
#endif
|
|
||||||
#define _accelerator_included
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a crash dump is uploaded.
|
|
||||||
*
|
|
||||||
* @param index Index of the crash.
|
|
||||||
* @param response HTTP response in plain text.
|
|
||||||
* @param responsesize HTTP response char buffer size.
|
|
||||||
*/
|
|
||||||
forward void Accelerator_OnCrashUploaded(int index, const char[] response, int responsesize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not edit below this line!
|
|
||||||
*/
|
|
||||||
public Extension __ext_accelerator =
|
|
||||||
{
|
|
||||||
name = "accelerator",
|
|
||||||
file = "accelerator.ext",
|
|
||||||
#if defined AUTOLOAD_EXTENSIONS
|
|
||||||
autoload = 1,
|
|
||||||
#else
|
|
||||||
autoload = 0,
|
|
||||||
#endif
|
|
||||||
#if defined REQUIRE_EXTENSIONS
|
|
||||||
required = 1,
|
|
||||||
#else
|
|
||||||
required = 0,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
97
scripting/accelerator_example.sp
Normal file
97
scripting/accelerator_example.sp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#include <sourcemod>
|
||||||
|
#include <accelerator>
|
||||||
|
|
||||||
|
#pragma newdecls required
|
||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
bool g_bLoggedCrashes = false;
|
||||||
|
Handle g_Timer = null;
|
||||||
|
|
||||||
|
public Plugin myinfo =
|
||||||
|
{
|
||||||
|
name = "Accelerator Example",
|
||||||
|
author = "caxanga334",
|
||||||
|
description = "Example Accelerator natives plugin.",
|
||||||
|
version = "1.0.0",
|
||||||
|
url = "https://github.com/asherkin/accelerator"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public void OnPluginStart()
|
||||||
|
{
|
||||||
|
RegAdminCmd("sm_listcrashes", Command_ListCrashes, ADMFLAG_RCON, "List all uploaded crash dumps.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnMapStart()
|
||||||
|
{
|
||||||
|
if (!g_bLoggedCrashes)
|
||||||
|
{
|
||||||
|
if (g_Timer == null)
|
||||||
|
{
|
||||||
|
g_Timer = CreateTimer(0.1, Timer_LogCrashes, .flags = TIMER_REPEAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called when the extension is done uploading crashes
|
||||||
|
public void Accelerator_OnDoneUploadingCrashes()
|
||||||
|
{
|
||||||
|
LogMessage("Accelerator is done uploading crashes!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Action Command_ListCrashes(int client, int args)
|
||||||
|
{
|
||||||
|
if (!Accelerator_IsDoneUploadingCrashes())
|
||||||
|
{
|
||||||
|
ReplyToCommand(client, "Accelerator is still uploading crashes, please wait!");
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
int max = Accelerator_GetUploadedCrashCount();
|
||||||
|
|
||||||
|
if (max == 0)
|
||||||
|
{
|
||||||
|
ReplyToCommand(client, "No crashes were uploaded!");
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
for (int i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
Accelerator_GetCrashHTTPResponse(i, buffer, sizeof(buffer));
|
||||||
|
ReplyToCommand(client, "Crash #%i: HTTP reponse: \"%s\".", i, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Action Timer_LogCrashes(Handle timer)
|
||||||
|
{
|
||||||
|
if (!Accelerator_IsDoneUploadingCrashes())
|
||||||
|
{
|
||||||
|
return Plugin_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int max = Accelerator_GetUploadedCrashCount();
|
||||||
|
|
||||||
|
if (max == 0)
|
||||||
|
{
|
||||||
|
LogMessage("No crashes were uploaded!");
|
||||||
|
g_Timer = null;
|
||||||
|
g_bLoggedCrashes = true;
|
||||||
|
return Plugin_Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
for (int i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
Accelerator_GetCrashHTTPResponse(i, buffer, sizeof(buffer));
|
||||||
|
LogMessage("Crash #%i: HTTP reponse: \"%s\".", i, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_Timer = null;
|
||||||
|
g_bLoggedCrashes = true;
|
||||||
|
return Plugin_Stop;
|
||||||
|
}
|
||||||
67
scripting/include/accelerator.inc
Normal file
67
scripting/include/accelerator.inc
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Accelerator's SourcePawn include file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined _accelerator_included
|
||||||
|
#endinput
|
||||||
|
#endif
|
||||||
|
#define _accelerator_included
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when Accelerator is done uploading crash dumps.
|
||||||
|
*/
|
||||||
|
forward void Accelerator_OnDoneUploadingCrashes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of crashes uploaded.
|
||||||
|
*
|
||||||
|
* @return Number of crashes uploaded.
|
||||||
|
*/
|
||||||
|
native int Accelerator_GetUploadedCrashCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if Accelerator is done uploading crashes.
|
||||||
|
*
|
||||||
|
* @return True if no more crashes will be uploaded, false if there are still crashes pending upload.
|
||||||
|
*/
|
||||||
|
native bool Accelerator_IsDoneUploadingCrashes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a crash's HTTP response from Accelerator's backend server.
|
||||||
|
*
|
||||||
|
* @note The response from the server can be anything and there is no guarantee a crash ID will be present.
|
||||||
|
* @param index The crash index, starts at 0 and goes up to Accelerator_GetUploadedCrashCount() - 1;
|
||||||
|
* @param buffer Buffer to store the crash HTTP response.
|
||||||
|
* @param size Size of the buffer parameter.
|
||||||
|
* @error Native called before Accelerator_IsDoneUploadingCrashes() returns true or invalid crash index passed.
|
||||||
|
*/
|
||||||
|
native void Accelerator_GetCrashHTTPResponse(int index, char[] buffer, int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not edit below this line!
|
||||||
|
*/
|
||||||
|
public Extension __ext_accelerator =
|
||||||
|
{
|
||||||
|
name = "accelerator",
|
||||||
|
file = "accelerator.ext",
|
||||||
|
#if defined AUTOLOAD_EXTENSIONS
|
||||||
|
autoload = 1,
|
||||||
|
#else
|
||||||
|
autoload = 0,
|
||||||
|
#endif
|
||||||
|
#if defined REQUIRE_EXTENSIONS
|
||||||
|
required = 1,
|
||||||
|
#else
|
||||||
|
required = 0,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !defined REQUIRE_EXTENSIONS
|
||||||
|
public __ext_accelerator_SetNTVOptional()
|
||||||
|
{
|
||||||
|
MarkNativeAsOptional("Accelerator_GetUploadedCrashCount");
|
||||||
|
MarkNativeAsOptional("Accelerator_IsDoneUploadingCrashes");
|
||||||
|
MarkNativeAsOptional("Accelerator_GetCrashHTTPResponse");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user