mirror of
https://github.com/asherkin/accelerator.git
synced 2025-12-06 18:08:30 +00:00
[Feature]: Add on crash uploaded SourceMod forward (#42)
* Squashed commit of the following:
commit c7efce2d6722b08e2ea719ce1a39f80747502f77
Author: caxanga334 <10157643+caxanga334@users.noreply.github.com>
Date: Sat Nov 22 22:35:24 2025 -0300
Fix Error
commit e8acf9f505aa26b007c5837d4075f649099f43c3
Author: caxanga334 <10157643+caxanga334@users.noreply.github.com>
Date: Sat Nov 22 22:23:57 2025 -0300
Fix Possible Memory Leak
commit 51e718922726c074c0e7a45f9d13c6a51e4b97eb
Author: caxanga334 <10157643+caxanga334@users.noreply.github.com>
Date: Sat Nov 22 22:13:55 2025 -0300
Add Upload Forward
* Update accelerator.inc
* Fix: Missing forwards.cpp in AMBuilder
* Refactor API
Forward notifies plugins when the extension is done uploading.
Plugins can fetch data from uploaded crashes via natives.
Added example plugin.
* Implement Requested Changes
* Fix Error
* Update Example Plugin
Removed timer example.
Added example of how to handle plugin late loads.
This commit is contained in:
parent
a661a6abb7
commit
87704dc53b
@ -9,7 +9,9 @@ builder.SetBuildFolder('package')
|
|||||||
folder_list = [
|
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',
|
||||||
]
|
]
|
||||||
|
|
||||||
# Are we build a x86_64 extension ?
|
# Are we build a x86_64 extension ?
|
||||||
@ -42,6 +44,20 @@ def CopyDirContent(src, dest):
|
|||||||
if item.is_file():
|
if item.is_file():
|
||||||
builder.AddCopy(item.path, dest_entry)
|
builder.AddCopy(item.path, dest_entry)
|
||||||
|
|
||||||
|
# Include files
|
||||||
|
CopyFiles('scripting/include', 'addons/sourcemod/scripting/include',
|
||||||
|
[
|
||||||
|
'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':
|
||||||
|
|||||||
@ -7,6 +7,8 @@ project = builder.LibraryProject('accelerator.ext')
|
|||||||
project.sources = [
|
project.sources = [
|
||||||
'extension.cpp',
|
'extension.cpp',
|
||||||
'MemoryDownloader.cpp',
|
'MemoryDownloader.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')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include <IWebternet.h>
|
#include <IWebternet.h>
|
||||||
#include "MemoryDownloader.h"
|
#include "MemoryDownloader.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"
|
||||||
@ -464,6 +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);
|
||||||
|
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);
|
||||||
@ -495,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1080,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()
|
||||||
@ -1117,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);
|
||||||
@ -1142,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];
|
||||||
@ -1321,6 +1351,7 @@ bool Accelerator::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
|||||||
|
|
||||||
void Accelerator::SDK_OnUnload()
|
void Accelerator::SDK_OnUnload()
|
||||||
{
|
{
|
||||||
|
extforwards::Shutdown();
|
||||||
plsys->RemovePluginsListener(this);
|
plsys->RemovePluginsListener(this);
|
||||||
|
|
||||||
#if defined _LINUX
|
#if defined _LINUX
|
||||||
@ -1336,9 +1367,21 @@ void Accelerator::SDK_OnUnload()
|
|||||||
delete handler;
|
delete handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Accelerator::SDK_OnAllLoaded()
|
||||||
|
{
|
||||||
|
extforwards::Init();
|
||||||
|
sharesys->RegisterLibrary(myself, "accelerator");
|
||||||
|
|
||||||
|
natives::Setup(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
|
||||||
@ -1499,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.
|
||||||
*
|
*
|
||||||
@ -49,6 +71,11 @@ public: // SDKExtension
|
|||||||
*/
|
*/
|
||||||
virtual void SDK_OnUnload();
|
virtual void SDK_OnUnload();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This is called once all known extensions have been loaded.
|
||||||
|
*/
|
||||||
|
virtual void SDK_OnAllLoaded();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called on server activation before plugins receive the OnServerLoad forward.
|
* @brief Called on server activation before plugins receive the OnServerLoad forward.
|
||||||
*
|
*
|
||||||
@ -68,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_
|
||||||
|
|||||||
36
extension/forwards.cpp
Normal file
36
extension/forwards.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
#include "extension.h"
|
||||||
|
#include "forwards.h"
|
||||||
|
|
||||||
|
|
||||||
|
static SourceMod::IForward* s_ondoneuploadingforward = nullptr;
|
||||||
|
|
||||||
|
static void OnDoneUploadingCallback(void* data)
|
||||||
|
{
|
||||||
|
if (s_ondoneuploadingforward) {
|
||||||
|
s_ondoneuploadingforward->Execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void extforwards::Init()
|
||||||
|
{
|
||||||
|
s_ondoneuploadingforward = forwards->CreateForward("Accelerator_OnDoneUploadingCrashes", SourceMod::ExecType::ET_Ignore, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void extforwards::Shutdown()
|
||||||
|
{
|
||||||
|
if (s_ondoneuploadingforward) {
|
||||||
|
forwards->ReleaseForward(s_ondoneuploadingforward);
|
||||||
|
s_ondoneuploadingforward = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void extforwards::CallOnDoneUploadingForward()
|
||||||
|
{
|
||||||
|
// It's obligatory to use AddFrameAction here because SourcePawn forwards can only be called from the server's main thread.
|
||||||
|
// AddFrameAction will do this for us and is also thread safe.
|
||||||
|
smutils->AddFrameAction(OnDoneUploadingCallback, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
16
extension/forwards.h
Normal file
16
extension/forwards.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef _INCLUDE_FORWARDS_H_
|
||||||
|
#define _INCLUDE_FORWARDS_H_
|
||||||
|
|
||||||
|
namespace extforwards
|
||||||
|
{
|
||||||
|
// Initialize the sourcepawn forwards.
|
||||||
|
void Init();
|
||||||
|
// Shutdown the sourcepawn forwards.
|
||||||
|
void Shutdown();
|
||||||
|
// Calls the on done uploadind forward. (thread safe)
|
||||||
|
void CallOnDoneUploadingForward();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#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::Setup(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));
|
||||||
|
}
|
||||||
11
extension/natives.h
Normal file
11
extension/natives.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _INCLUDE_NATIVES_H_
|
||||||
|
#define _INCLUDE_NATIVES_H_
|
||||||
|
|
||||||
|
|
||||||
|
namespace natives
|
||||||
|
{
|
||||||
|
// Called during the load process to setup the extension natives
|
||||||
|
void Setup(std::vector<sp_nativeinfo_t>& vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !_INCLUDE_NATIVES_H_
|
||||||
@ -58,7 +58,7 @@
|
|||||||
//#define SMEXT_CONF_METAMOD
|
//#define SMEXT_CONF_METAMOD
|
||||||
|
|
||||||
/** Enable interfaces you want to use here by uncommenting lines */
|
/** Enable interfaces you want to use here by uncommenting lines */
|
||||||
//#define SMEXT_ENABLE_FORWARDSYS
|
#define SMEXT_ENABLE_FORWARDSYS
|
||||||
//#define SMEXT_ENABLE_HANDLESYS
|
//#define SMEXT_ENABLE_HANDLESYS
|
||||||
//#define SMEXT_ENABLE_PLAYERHELPERS
|
//#define SMEXT_ENABLE_PLAYERHELPERS
|
||||||
//#define SMEXT_ENABLE_DBMANAGER
|
//#define SMEXT_ENABLE_DBMANAGER
|
||||||
|
|||||||
76
scripting/accelerator_example.sp
Normal file
76
scripting/accelerator_example.sp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include <sourcemod>
|
||||||
|
#include <accelerator>
|
||||||
|
|
||||||
|
#pragma newdecls required
|
||||||
|
#pragma semicolon 1
|
||||||
|
|
||||||
|
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.");
|
||||||
|
|
||||||
|
// Call the forward manually. (For late loading plugins)
|
||||||
|
if (Accelerator_IsDoneUploadingCrashes())
|
||||||
|
{
|
||||||
|
Accelerator_OnDoneUploadingCrashes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called when the extension is done uploading crashes
|
||||||
|
public void Accelerator_OnDoneUploadingCrashes()
|
||||||
|
{
|
||||||
|
LogMessage("Accelerator is done uploading crashes!");
|
||||||
|
|
||||||
|
int max = Accelerator_GetUploadedCrashCount();
|
||||||
|
|
||||||
|
if (max == 0)
|
||||||
|
{
|
||||||
|
LogMessage("No crashes were uploaded!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[512];
|
||||||
|
|
||||||
|
for (int i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
Accelerator_GetCrashHTTPResponse(i, buffer, sizeof(buffer));
|
||||||
|
LogMessage("Crash #%i: HTTP reponse: \"%s\".", i, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Admin command to list 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;
|
||||||
|
}
|
||||||
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