mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-24 17:06:17 +02:00
A mod with a reskate-plugin.json is a plugin: Luau scripts that run in their own VM, with only
the reskate API ReSkate registers for them. Luau 0.741 is vendored in External/luau (the VM and
compiler only: no native code generation, no loadstring, io or C modules).
- Limits: 64 MB of memory, 50 ms a call, 2 ms a tick on average (over it for 3 s stops it),
more than 5 errors in 10 s stops it, 50 log lines a second. A plugin over a limit cannot catch
it in a pcall and carry on.
- API: reskate.log, on (load, unload, tick, level_loaded, level_unloading), timers, the level,
its own package's files and JSON, require inside the package; console.command and print
("console"); storage get, set, add and keys ("storage"), 1 MB in
%LOCALAPPDATA%\ReSkate\Plugins\<mod>\storage.json.
- Found every 2 s among the mods mods.json leaves on: switching a mod, or changing a plugin's
files, loads, unloads or reloads it without a restart. A package holding a program is refused.
- plugin list, commands, reload, off and on in the console. A plugin cannot take a name of
ReSkate's own commands.
- Tests: DINGOSDK_BUILD_PLUGIN_TESTS, including plugins written to break the sandbox.
323 lines
6.4 KiB
C++
323 lines
6.4 KiB
C++
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
#pragma once
|
|
|
|
#include "Luau/Common.h"
|
|
|
|
#include <initializer_list>
|
|
#include <new>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace Luau
|
|
{
|
|
|
|
template<typename T, unsigned N>
|
|
class SmallVector
|
|
{
|
|
static_assert(std::is_nothrow_move_constructible<T>::value, "T must be nothrow move constructible");
|
|
|
|
public:
|
|
using iterator = T*;
|
|
using const_iterator = const T*;
|
|
using value_type = T;
|
|
using reference = T&;
|
|
using const_reference = const T&;
|
|
|
|
SmallVector()
|
|
{
|
|
ptr = reinterpret_cast<T*>(storage);
|
|
}
|
|
|
|
SmallVector(std::initializer_list<T> init)
|
|
: SmallVector()
|
|
{
|
|
LUAU_ASSERT(unsigned(init.size()) == init.size());
|
|
|
|
reserve(unsigned(init.size()));
|
|
|
|
std::uninitialized_copy(init.begin(), init.end(), ptr);
|
|
count = unsigned(init.size());
|
|
}
|
|
|
|
SmallVector(const SmallVector& other)
|
|
: SmallVector()
|
|
{
|
|
reserve(other.count);
|
|
|
|
std::uninitialized_copy(other.begin(), other.end(), ptr);
|
|
count = other.count;
|
|
}
|
|
|
|
SmallVector(SmallVector&& other) noexcept
|
|
: SmallVector()
|
|
{
|
|
if (!other.is_heap())
|
|
{
|
|
std::uninitialized_move(other.begin(), other.end(), ptr);
|
|
count = other.count;
|
|
|
|
other.clear();
|
|
}
|
|
else
|
|
{
|
|
ptr = other.ptr;
|
|
max = other.max;
|
|
count = other.count;
|
|
|
|
other.ptr = reinterpret_cast<T*>(other.storage);
|
|
other.max = N;
|
|
other.count = 0;
|
|
}
|
|
}
|
|
|
|
~SmallVector()
|
|
{
|
|
clear();
|
|
|
|
if (is_heap())
|
|
::operator delete(ptr);
|
|
}
|
|
|
|
SmallVector& operator=(const SmallVector& other)
|
|
{
|
|
if (this == &other)
|
|
return *this;
|
|
|
|
if (other.count <= count)
|
|
{
|
|
std::copy(other.begin(), other.end(), begin());
|
|
|
|
while (count > other.count)
|
|
ptr[--count].~T();
|
|
}
|
|
else
|
|
{
|
|
std::copy(other.begin(), other.begin() + count, begin());
|
|
|
|
reserve(other.count);
|
|
|
|
std::uninitialized_copy(other.begin() + count, other.end(), ptr + count);
|
|
count = other.count;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
SmallVector& operator=(SmallVector&& other) noexcept
|
|
{
|
|
if (this != &other)
|
|
{
|
|
clear();
|
|
|
|
if (!other.is_heap())
|
|
{
|
|
std::uninitialized_move(other.begin(), other.end(), begin());
|
|
count = other.count;
|
|
|
|
other.clear();
|
|
}
|
|
else
|
|
{
|
|
if (is_heap())
|
|
::operator delete(ptr);
|
|
|
|
ptr = other.ptr;
|
|
max = other.max;
|
|
count = other.count;
|
|
|
|
other.ptr = reinterpret_cast<T*>(other.storage);
|
|
other.max = N;
|
|
other.count = 0;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename... Args>
|
|
reference emplace_back(Args&&... args)
|
|
{
|
|
if (count == max)
|
|
grow(count + 1);
|
|
|
|
new (&ptr[count]) T(std::forward<Args>(args)...);
|
|
return ptr[count++];
|
|
}
|
|
|
|
void push_back(const T& val)
|
|
{
|
|
if (count == max)
|
|
grow(count + 1);
|
|
|
|
new (&ptr[count]) T(val);
|
|
count++;
|
|
}
|
|
|
|
void push_back(T&& val)
|
|
{
|
|
if (count == max)
|
|
grow(count + 1);
|
|
|
|
new (&ptr[count]) T(std::move(val));
|
|
count++;
|
|
}
|
|
|
|
T& front()
|
|
{
|
|
LUAU_ASSERT(count > 0);
|
|
return ptr[0];
|
|
}
|
|
|
|
const T& front() const
|
|
{
|
|
LUAU_ASSERT(count > 0);
|
|
return ptr[0];
|
|
}
|
|
|
|
T& back()
|
|
{
|
|
LUAU_ASSERT(count > 0);
|
|
return ptr[count - 1];
|
|
}
|
|
|
|
const T& back() const
|
|
{
|
|
LUAU_ASSERT(count > 0);
|
|
return ptr[count - 1];
|
|
}
|
|
|
|
bool empty() const noexcept
|
|
{
|
|
return count == 0;
|
|
}
|
|
|
|
unsigned size() const noexcept
|
|
{
|
|
return count;
|
|
}
|
|
|
|
unsigned capacity() const noexcept
|
|
{
|
|
return max;
|
|
}
|
|
|
|
void pop_back()
|
|
{
|
|
LUAU_ASSERT(count > 0);
|
|
ptr[--count].~T();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
while (count > 0)
|
|
ptr[--count].~T();
|
|
}
|
|
|
|
T* begin()
|
|
{
|
|
return ptr;
|
|
}
|
|
|
|
const T* begin() const
|
|
{
|
|
return ptr;
|
|
}
|
|
|
|
T* end()
|
|
{
|
|
return ptr + count;
|
|
}
|
|
|
|
const T* end() const
|
|
{
|
|
return ptr + count;
|
|
}
|
|
|
|
T* data()
|
|
{
|
|
return ptr;
|
|
}
|
|
const T* data() const
|
|
{
|
|
return ptr;
|
|
}
|
|
|
|
T& operator[](size_t index)
|
|
{
|
|
LUAU_ASSERT(index < count);
|
|
|
|
return ptr[index];
|
|
}
|
|
|
|
const T& operator[](size_t index) const
|
|
{
|
|
LUAU_ASSERT(index < count);
|
|
|
|
return ptr[index];
|
|
}
|
|
|
|
void resize(unsigned newSize)
|
|
{
|
|
if (newSize > count)
|
|
{
|
|
if (newSize > max)
|
|
grow(newSize);
|
|
|
|
for (unsigned i = count; i < newSize; ++i)
|
|
new (&ptr[i]) T();
|
|
}
|
|
else
|
|
{
|
|
while (count > newSize)
|
|
ptr[--count].~T();
|
|
}
|
|
|
|
count = newSize;
|
|
}
|
|
|
|
void reserve(unsigned reserveSize)
|
|
{
|
|
if (reserveSize > max)
|
|
grow(reserveSize);
|
|
}
|
|
|
|
private:
|
|
bool is_heap() const
|
|
{
|
|
return ptr != reinterpret_cast<const T*>(storage);
|
|
}
|
|
|
|
void grow(unsigned newSize)
|
|
{
|
|
if (max + (max >> 1) > newSize)
|
|
newSize = max + (max >> 1);
|
|
else
|
|
newSize += 4;
|
|
|
|
LUAU_ASSERT(newSize < 0x40000000);
|
|
|
|
void* raw = ::operator new(newSize * sizeof(T));
|
|
T* newData = static_cast<T*>(raw);
|
|
|
|
std::uninitialized_move(ptr, ptr + count, newData);
|
|
|
|
for (unsigned i = 0; i < count; ++i)
|
|
ptr[i].~T();
|
|
|
|
if (is_heap())
|
|
::operator delete(ptr);
|
|
|
|
ptr = newData;
|
|
max = newSize;
|
|
}
|
|
|
|
T* ptr = nullptr;
|
|
unsigned count = 0;
|
|
unsigned max = N;
|
|
|
|
alignas(T) unsigned char storage[N * sizeof(T)];
|
|
};
|
|
|
|
} // namespace Luau
|