Initial commit

This commit is contained in:
2025-12-17 16:47:48 +00:00
commit 13813f3363
4964 changed files with 1079753 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
#include "AppSettings.hpp"
#include <QString>
#ifndef SKIP_APP_SETTINGS_LOADING
#include "Utility/StandardOut.hpp"
#include "Utility/Statistics.hpp"
#endif // SKIP_APP_SETTINGS_LOADING
#include <boost/algorithm/string.hpp>
#include <filesystem>
static const char* kAppSettingsFileName = "AppSettings.ini";
namespace fs = std::filesystem;
AppSettings::AppSettings(const std::string& appDir)
: m_pSettings(nullptr)
{
this->appDir = appDir;
}
AppSettings::~AppSettings()
{
delete m_pSettings;
}
bool AppSettings::load()
{
if (appDir.empty())
return false;
delete m_pSettings;
std::string path = appDir + "/" + kAppSettingsFileName;
#ifndef SKIP_APP_SETTINGS_LOADING
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_SYSTEM, "Loading AppSettings from %s", path.c_str());
#endif
m_pSettings = new QSettings(QString::fromStdString(appDir + "/" + kAppSettingsFileName), QSettings::IniFormat);
bool success = m_pSettings->status() == QSettings::NoError;
if (success)
{
m_pSettings->sync();
m_pSettings->setFallbacksEnabled(true);
// hack for bootstrapper who can't deal with allat
#ifndef SKIP_APP_SETTINGS_LOADING
std::string assetFolder = get("Aya", "ContentFolder").value_or(appDir + "/content");
SetAssetFolder(assetFolder);
SetTrustCheckURL(get("Aya", "TrustCheckUrl").value_or(""));
if (GetTrustCheckURL().empty())
SetUsingTrustCheck(false);
if (has("Aya", "InsecureMode"))
{
std::string insecureMode = get("Aya", "InsecureMode").value_or("false");
boost::algorithm::to_lower(insecureMode);
SetInsecureMode(insecureMode == "true" || insecureMode == "1" || insecureMode == "yes");
}
if (has("Aya", "VerboseLogging"))
{
std::string verboseLogging = get("Aya", "VerboseLogging").value_or("false");
boost::algorithm::to_lower(verboseLogging);
SetVerboseLogging(verboseLogging == "true" || verboseLogging == "1" || verboseLogging == "yes");
}
if (hasGroup("Instance"))
{
SetBaseURL(get("Instance", "BaseUrl").value_or(""));
SetInstanceAccessKey(get("Instance", "AccessKey").value_or(""));
}
if (GetBaseURL().empty())
{
SetUsingInstance(false);
SetFetchLocalClientSettings(true);
}
else
{
SetUsingInstance(true);
SetFetchLocalClientSettings(false);
}
if (hasGroup("MasterServer"))
{
SetMasterServerURL(get("MasterServer", "BaseUrl").value_or(""));
SetMasterServerKey(get("MasterServer", "AccessKey").value_or(""));
}
SetUsingMasterServer(!GetMasterServerURL().empty());
#endif // SKIP_APP_SETTINGS_LOADING
}
return success;
}
std::optional<std::string> AppSettings::get(const std::string& group, const std::string& key) const
{
m_pSettings->beginGroup(QString::fromStdString(group));
QVariant value = m_pSettings->value(QString::fromStdString(key));
m_pSettings->endGroup();
if (value.isValid() && value.type() == QVariant::String)
return value.toString().toStdString();
return std::nullopt;
}
bool AppSettings::hasGroup(const std::string& group)
{
return m_pSettings->childGroups().contains(QString::fromStdString(group));
}
bool AppSettings::has(const std::string& group, const std::string& key)
{
if (!this->hasGroup(group))
return false;
m_pSettings->beginGroup(QString::fromStdString(group));
QVariant value = m_pSettings->value(QString::fromStdString(key));
m_pSettings->endGroup();
return value.isValid();
}
void AppSettings::set(const std::string& group, const std::string& key, const std::string& value)
{
m_pSettings->beginGroup(QString::fromStdString(group));
m_pSettings->setValue(QString::fromStdString(key), QString::fromStdString(value));
m_pSettings->endGroup();
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <QSettings>
#include <string>
#include <optional>
class AppSettings
{
public:
AppSettings(const std::string& appDir);
virtual ~AppSettings();
bool load();
std::optional<std::string> get(const std::string& group, const std::string& key) const;
bool hasGroup(const std::string& group);
bool has(const std::string& group, const std::string& key);
void set(const std::string& group, const std::string& key, const std::string& value);
protected:
QSettings* m_pSettings;
std::string appDir;
};

View File

View File

View File

@@ -0,0 +1,635 @@
#ifndef AYA_STUDIO
#undef min
#undef max
#include "format_string.hpp"
#include "AyaFormat.hpp"
#include "Debug.hpp"
#include "boost.hpp"
#include "Utility/StandardOut.hpp"
#include "Utility/FileSystem.hpp"
#include "Utility/Guid.hpp"
#include "Utility/Http.hpp"
#include "Utility/Statistics.hpp"
#include "debugAssert.hpp"
#include <direct.h>
#include "atltime.h"
#include "atlfile.h"
#include "TaskScheduler.hpp"
#include "DumpErrorUploader.hpp"
#include "Log.hpp"
#include "FastLog.hpp"
#include <Windows.h>
#include <DbgHelp.h>
#include <string.h>
#include <atlbase.h>
#include <boost/format.hpp>
LOGGROUP(CrashReporterInit)
bool LogManager::logsEnabled = false; // to be honest we only really need crash dmps & the logs outputted are not working
MainLogManager* LogManager::mainLogManager = NULL;
Aya::mutex MainLogManager::fastLogChannelsLock;
static const ATL::CPath& DoGetPath()
{
static ATL::CPath path(CString(Aya::FileSystem::getUserDirectory(true, Aya::DirAppData, "logs").native().c_str()));
return path;
}
void InitPath()
{
DoGetPath();
}
std::string GetAppVersion()
{
CVersionInfo vi;
FASTLOG1(FLog::CrashReporterInit, "Getting app version, module handle: %p", _AtlBaseModule.m_hInst);
vi.Load(_AtlBaseModule.m_hInst);
return vi.GetFileVersionAsString();
}
const ATL::CPath& LogManager::GetLogPath() const
{
static boost::once_flag flag = BOOST_ONCE_INIT;
boost::call_once(&InitPath, flag);
return DoGetPath();
}
const std::string LogManager::GetLogPathString() const
{
CStringA path = (LPCTSTR)GetLogPath();
return std::string(path.GetString());
}
void MainLogManager::fastLogMessage(FLog::Channel id, const char* message)
{
Aya::mutex::scoped_lock lock(fastLogChannelsLock);
if (mainLogManager)
{
if (id >= mainLogManager->fastLogChannels.size())
mainLogManager->fastLogChannels.resize(id + 1, NULL);
if (mainLogManager->fastLogChannels[id] == NULL)
{
mainLogManager->fastLogChannels[id] = new Aya::Log(mainLogManager->getFastLogFileName(id).c_str(), "Log Channel");
}
mainLogManager->fastLogChannels[id]->writeEntry(Aya::Log::Information, message);
}
}
std::string MainLogManager::getSessionId()
{
std::string id = guid;
return id;
}
std::string MainLogManager::getCrashEventName()
{
#ifdef WIN32
FASTLOG(FLog::CrashReporterInit, "Getting crash event name");
std::string path = GetLogPathString();
std::string fileName = "log_";
fileName += getSessionId();
fileName += " ";
fileName += GetAppVersion();
fileName += crashEventExtention;
path.append(fileName);
return path;
#endif
return "";
}
std::string MainLogManager::getLogFileName()
{
#ifdef WIN32
std::string path = GetLogPathString();
std::string fileName = "log_";
fileName += getSessionId();
fileName += ".txt";
path.append(fileName);
return path;
#endif
return "";
}
std::string MainLogManager::getFastLogFileName(FLog::Channel channelId)
{
#ifdef WIN32
std::string path = GetLogPathString();
std::string filename = Aya::format("log_%s_%d.txt", getSessionId().c_str(), channelId);
path.append(filename);
return path;
#endif
return "";
}
std::string MainLogManager::MakeLogFileName(const char* postfix)
{
#ifdef WIN32
std::string path = GetLogPathString();
std::string fileName = "log_";
fileName += getSessionId();
fileName += postfix;
fileName += ".txt";
path.append(fileName);
return path;
#endif
return "";
}
std::string ThreadLogManager::getLogFileName()
{
#ifdef WIN32
std::string fileName = mainLogManager->getLogFileName();
std::string id = Aya::format("_%s_%d", name.c_str(), threadID);
fileName.insert(fileName.size() - 4, id);
return fileName;
#endif
return "";
}
Aya::Log* LogManager::getLog()
{
if (!logsEnabled)
return NULL;
if (log == NULL)
{
log = new Aya::Log(getLogFileName().c_str(), name.c_str());
// TODO: delete an old log that isn't in use
}
return log;
}
Aya::Log* MainLogManager::provideLog()
{
if (GetCurrentThreadId() == threadID)
return this->getLog();
return ThreadLogManager::getCurrent()->getLog();
}
#include <process.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#define MAX_CONSOLE_LINES 250;
HANDLE g_hConsoleOut; // Handle to debug console
RobloxCrashReporter::RobloxCrashReporter(const char* outputPath, const char* appName, const char* crashExtention)
{
controls.minidumpType = MiniDumpWithDataSegs;
controls.minidumpType |= MiniDumpWithIndirectlyReferencedMemory;
// null terminate just in case long paths & make safe
strncpy(controls.pathToMinidump, outputPath, sizeof(controls.pathToMinidump) - 1);
controls.pathToMinidump[sizeof(controls.pathToMinidump) - 1] = '\0';
strncpy(controls.appName, appName, sizeof(controls.appName) - 1);
controls.appName[sizeof(controls.appName) - 1] = '\0';
strncpy(controls.appVersion, GetAppVersion().c_str(), sizeof(controls.appVersion) - 1);
controls.appVersion[sizeof(controls.appVersion) - 1] = '\0';
strncpy(controls.crashExtention, crashExtention, sizeof(controls.crashExtention) - 1);
controls.crashExtention[sizeof(controls.crashExtention) - 1] = '\0';
}
bool RobloxCrashReporter::silent;
LONG RobloxCrashReporter::ProcessException(struct _EXCEPTION_POINTERS* info, bool noMsg)
{
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "StartProcessException...");
LONG result = __super::ProcessException(info, noMsg);
static bool showedMessage = silent;
if (!showedMessage && !noMsg)
{
showedMessage = true;
::MessageBoxA(NULL, "An unexpected error occurred and " AYA_PROJECT_NAME " needs to quit. We're sorry!", AYA_PROJECT_NAME " Crash", MB_OK);
}
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "DoneProcessException");
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "Uploading .crashevent...");
DumpErrorUploader::UploadCrashEventFile(info);
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, "Done uploading .crashevent...");
return result;
}
void RobloxCrashReporter::logEvent(const char* msg)
{
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, msg);
}
void MainLogManager::WriteCrashDump()
{
std::string appName = "log_";
appName += getSessionId();
crashReporter.reset(new RobloxCrashReporter(GetLogPathString().c_str(), appName.c_str(), crashExtention));
crashReporter->Start();
};
bool MainLogManager::CreateFakeCrashDump()
{
if (!crashReporter)
{
// start the service if not started.
WriteCrashDump();
}
// First, write FastLog
char dumpFilepath[_MAX_PATH];
if (FAILED(crashReporter->GenerateDmpFileName(dumpFilepath, _MAX_PATH, true)))
{
return false;
}
FLog::WriteFastLogDump(dumpFilepath, 2000);
if (FAILED(crashReporter->GenerateDmpFileName(dumpFilepath, _MAX_PATH)))
{
return false;
}
HANDLE hFile = CreateFileA(dumpFilepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
DWORD cb;
WriteFile(hFile, "Fake", 5, &cb, NULL);
CloseHandle(hFile);
return true;
}
void MainLogManager::EnableImmediateCrashUpload(bool enabled)
{
if (crashReporter)
{
crashReporter->EnableImmediateUpload(enabled);
}
}
void MainLogManager::DisableHangReporting()
{
if (crashReporter)
{
crashReporter->DisableHangReporting();
}
}
void MainLogManager::NotifyFGThreadAlive()
{
if (crashReporter)
{
#if 0
// for debugging only:
static int alivecount = 0;
if(alivecount++ % 60 == 0)
{
CString eventMessage;
eventMessage.Format("FGAlive %d", alivecount);
LogManager::ReportEvent(EVENTLOG_INFORMATION_TYPE, eventMessage);
}
#endif
crashReporter->NotifyAlive();
}
}
static void purecallHandler(void)
{
#ifdef _DEBUG
_CrtDbgBreak();
#endif
// Cause a crash
AYACRASH();
}
MainLogManager::MainLogManager(LPCTSTR productName, const char* crashExtention, const char* crashEventExtention)
: LogManager("Aya")
, crashExtention(crashExtention)
, crashEventExtention(crashEventExtention)
, gameState(MainLogManager::GameState::UN_INITIALIZED)
{
Aya::Guid::generateRBXGUID(guid);
AYAASSERT(mainLogManager == NULL);
mainLogManager = this;
Aya::Log::setLogProvider(this);
Aya::setAssertionHook(&MainLogManager::handleDebugAssert);
Aya::setFailureHook(&MainLogManager::handleFailure);
_set_purecall_handler(purecallHandler);
FLog::SetExternalLogFunc(fastLogMessage);
}
MainLogManager* LogManager::getMainLogManager()
{
return mainLogManager;
}
ThreadLogManager::ThreadLogManager()
: LogManager(Aya::get_thread_name())
{
}
ThreadLogManager::~ThreadLogManager() {}
static float getThisYearTimeInMinutes(SYSTEMTIME time)
{
return (time.wMonth * 43829.0639f) + (time.wDay * 1440) + (time.wHour * 60) + time.wMinute;
}
MainLogManager::~MainLogManager()
{
Aya::mutex::scoped_lock lock(fastLogChannelsLock);
FLog::SetExternalLogFunc(NULL);
for (std::size_t i = 0; i < fastLogChannels.size(); i++)
delete fastLogChannels[i];
mainLogManager = NULL;
}
LogManager::~LogManager()
{
if (log != NULL)
{
std::string logFile = log->logFile;
delete log; // this will close the file so that we can move it
log = NULL;
}
}
inline HRESULT WINAPI RbxReportError(
const CLSID& clsid, LPCSTR lpszDesc, DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
{
ATLASSERT(lpszDesc != NULL);
if (lpszDesc == NULL)
return E_POINTER;
USES_CONVERSION_EX;
CString strDesc(lpszDesc);
CComBSTR desc = strDesc.AllocSysString(); // Convert CString to BSTR
if (desc == NULL)
return E_OUTOFMEMORY;
CComBSTR helpFile = NULL;
if (lpszHelpFile != NULL)
{
CString strHelpFile(lpszHelpFile);
helpFile = strHelpFile.AllocSysString(); // Convert CString to BSTR
if (helpFile == NULL)
return E_OUTOFMEMORY;
}
return AtlSetErrorInfo(clsid, desc.Detach(), dwHelpID, helpFile.Detach(), iid, hRes, NULL);
}
inline HRESULT WINAPI RbxReportError(
const CLSID& clsid, UINT nID, const IID& iid = GUID_NULL, HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
{
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), 0, NULL, iid, hRes, hInst);
}
inline HRESULT WINAPI RbxReportError(const CLSID& clsid, UINT nID, DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
{
return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), dwHelpID, lpszHelpFile, iid, hRes, hInst);
}
inline HRESULT WINAPI RbxReportError(const CLSID& clsid, LPCSTR lpszDesc, const IID& iid = GUID_NULL, HRESULT hRes = 0)
{
return RbxReportError(clsid, lpszDesc, 0, NULL, iid, hRes);
}
inline HRESULT WINAPI RbxReportError(const CLSID& clsid, LPCOLESTR lpszDesc, const IID& iid = GUID_NULL, HRESULT hRes = 0)
{
return AtlSetErrorInfo(clsid, lpszDesc, 0, NULL, iid, hRes, NULL);
}
inline HRESULT WINAPI RbxReportError(
const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
{
return AtlSetErrorInfo(clsid, lpszDesc, dwHelpID, lpszHelpFile, iid, hRes, NULL);
}
HRESULT LogManager::ReportCOMError(const CLSID& clsid, LPCOLESTR lpszDesc, HRESULT hRes)
{
return RbxReportError(clsid, lpszDesc, GUID_NULL, hRes);
}
HRESULT LogManager::ReportCOMError(const CLSID& clsid, LPCSTR lpszDesc, HRESULT hRes)
{
return RbxReportError(clsid, lpszDesc, GUID_NULL, hRes);
}
HRESULT LogManager::ReportCOMError(const CLSID& clsid, HRESULT hRes)
{
std::string message = Aya::format("HRESULT 0x%X", hRes);
LogManager::ReportEvent(EVENTLOG_ERROR_TYPE, message.c_str());
return RbxReportError(clsid, message.c_str(), GUID_NULL, hRes);
}
#ifdef _MFC_VER
HRESULT LogManager::ReportCOMError(const CLSID& clsid, CException* exception)
{
CString fullError;
HRESULT hr = COleException::Process(exception);
CString sError;
if (exception->GetErrorMessage(sError.GetBuffer(1024), 1023))
{
sError.ReleaseBuffer();
fullError.Format("%s (0x%X)", sError, hr);
}
else
fullError.Format("Error 0x%X", hr);
LogManager::ReportEvent(EVENTLOG_ERROR_TYPE, fullError);
return RbxReportError(clsid, fullError, GUID_NULL, hr);
}
#endif
bool MainLogManager::handleG3DDebugAssert(
const char* _expression, const std::string& message, const char* filename, int lineNumber, bool useGuiPrompt)
{
return handleDebugAssert(_expression, filename, lineNumber);
}
bool MainLogManager::handleDebugAssert(const char* expression, const char* filename, int lineNumber)
{
#ifdef _DEBUG
LogManager::ReportEvent(EVENTLOG_WARNING_TYPE,
std::string("Assertion failed: " + std::string(expression) + "\n" + std::string(filename) + "(" + std::to_string(lineNumber) + ")").c_str());
AYACRASH();
return true;
#else
return false;
#endif
}
bool MainLogManager::handleG3DFailure(const char* _expression, const std::string& message, const char* filename, int lineNumber, bool useGuiPrompt)
{
return handleFailure(_expression, filename, lineNumber);
}
bool MainLogManager::handleFailure(const char* expression, const char* filename, int lineNumber)
{
#ifdef _DEBUG
_CrtDbgBreak();
#endif
// Cause a crash
AYACRASH();
return false;
}
HRESULT LogManager::ReportExceptionAsCOMError(const CLSID& clsid, std::exception const& exp)
{
return ReportCOMError(clsid, exp.what());
}
void LogManager::ReportException(std::exception const& exp)
{
Aya::StandardOut::singleton()->print(Aya::MESSAGE_ERROR, exp);
}
void LogManager::ReportLastError(LPCSTR message)
{
DWORD error = GetLastError();
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_ERROR, "%s, GetLastError=%d", message, error);
}
void LogManager::ReportEvent(WORD type, LPCSTR message)
{
switch (type)
{
case EVENTLOG_SUCCESS:
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_INFO, "%s", message);
break;
case EVENTLOG_ERROR_TYPE:
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_ERROR, "%s", message);
break;
case EVENTLOG_INFORMATION_TYPE:
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_INFO, "%s", message);
break;
case EVENTLOG_AUDIT_SUCCESS:
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_INFO, "%s", message);
break;
case EVENTLOG_AUDIT_FAILURE:
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_ERROR, "%s", message);
break;
}
#ifdef _DEBUG
switch (type)
{
case EVENTLOG_SUCCESS:
ATLTRACE("EVENTLOG_SUCCESS %s\n", message);
break;
case EVENTLOG_ERROR_TYPE:
ATLTRACE("EVENTLOG_ERROR_TYPE %s\n", message);
break;
case EVENTLOG_INFORMATION_TYPE:
ATLTRACE("EVENTLOG_INFORMATION_TYPE %s\n", message);
break;
case EVENTLOG_AUDIT_SUCCESS:
ATLTRACE("EVENTLOG_AUDIT_SUCCESS %s\n", message);
break;
case EVENTLOG_AUDIT_FAILURE:
ATLTRACE("EVENTLOG_AUDIT_FAILURE %s\n", message);
break;
}
#endif
}
void LogManager::ReportEvent(WORD type, LPCSTR message, LPCSTR fileName, int lineNumber)
{
// CString m;
// m.Format(convert_s2w("%s\n%s(%d)"), message, fileName, lineNumber);
// LogManager::ReportEvent(type, m);
}
#ifdef _MFC_VER
void LogManager::ReportEvent(WORD type, HRESULT hr, LPCSTR fileName, int lineNumber)
{
COleException e;
e.m_sc = hr;
TCHAR s[1024];
e.GetErrorMessage(s, 1024);
CString m;
m.Format("HRESULT = %d: %s\n%s(%d)", hr, s, fileName, lineNumber);
LogManager::ReportEvent(type, m);
}
#endif
namespace log_detail
{
boost::once_flag once_init = BOOST_ONCE_INIT;
static boost::thread_specific_ptr<ThreadLogManager>* ts;
void init(void)
{
static boost::thread_specific_ptr<ThreadLogManager> value;
ts = &value;
}
} // namespace log_detail
ThreadLogManager* ThreadLogManager::getCurrent()
{
boost::call_once(log_detail::init, log_detail::once_init);
ThreadLogManager* logManager = log_detail::ts->get();
if (!logManager)
{
logManager = new ThreadLogManager();
log_detail::ts->reset(logManager);
}
return logManager;
}
#endif

View File

@@ -0,0 +1,157 @@
#pragma once
#if defined(_WIN32) || defined(_WIN64)
#include "intrusive_ptr_target.hpp"
#include <Windows.h>
#include <atlpath.h>
#include "Log.hpp"
#include "boost.hpp"
#include "Utility/Exception.hpp"
#include "CrashReporter.hpp"
#include "boost/scoped_ptr.hpp"
#include <vector>
#include "threadsafe.hpp"
class LogManager
{
Aya::Log* log;
static bool logsEnabled;
protected:
const DWORD threadID;
std::string name;
static class MainLogManager* mainLogManager;
public:
Aya::Log* getLog();
static MainLogManager* getMainLogManager();
#ifdef _MFC_VER
static HRESULT ReportCOMError(const CLSID& clsid, CException* exception);
#endif
static HRESULT ReportCOMError(const CLSID& clsid, HRESULT hRes);
static HRESULT ReportCOMError(const CLSID& clsid, LPCOLESTR lpszDesc, HRESULT hRes = 0);
static HRESULT ReportCOMError(const CLSID& clsid, LPCSTR lpszDesc, HRESULT hRes = 0);
static HRESULT ReportExceptionAsCOMError(const CLSID& clsid, std::exception const& exp);
static void ReportException(std::exception const& exp);
static void ReportLastError(LPCSTR message);
static void ReportEvent(WORD type, LPCSTR message);
static void ReportEvent(WORD type, LPCSTR message, LPCSTR fileName, int lineNumber);
static void ReportEvent(WORD type, HRESULT hr, LPCSTR fileName, int lineNumber);
const ATL::CPath& GetLogPath() const;
const std::string GetLogPathString() const;
virtual ~LogManager();
virtual std::string getLogFileName() = 0;
protected:
LogManager(const char* name)
: log(NULL)
, name(name)
, threadID(GetCurrentThreadId()) {};
};
class RobloxCrashReporter : public CrashReporter
{
public:
static bool silent;
RobloxCrashReporter(const char* outputPath, const char* appName, const char* crashExtention);
LONG ProcessException(struct _EXCEPTION_POINTERS* info, bool noMsg);
protected:
/*override*/ void logEvent(const char* msg);
};
class MainLogManager
: public Aya::ILogProvider
, public LogManager
{
boost::scoped_ptr<RobloxCrashReporter> crashReporter;
std::vector<Aya::Log*> fastLogChannels;
static Aya::mutex fastLogChannelsLock;
const char* crashExtention;
const char* crashEventExtention;
public:
MainLogManager(LPCTSTR productName, const char* crashExtention, const char* crashEventExtention); // used for main thread
~MainLogManager();
Aya::Log* provideLog();
virtual std::string getLogFileName();
std::string getFastLogFileName(FLog::Channel channelId);
std::string MakeLogFileName(const char* postfix);
bool hasErrorLogs() const;
std::vector<std::string> gatherScriptCrashLogs();
void WriteCrashDump();
// triggers upload of log files on next start.
bool CreateFakeCrashDump();
void NotifyFGThreadAlive(); // for deadlock reporting. call every second.
void DisableHangReporting();
void EnableImmediateCrashUpload(bool enabled);
// returns HEX string that will be part of all the log/dumps output for this session.
std::string getSessionId();
std::string getCrashEventName();
static void fastLogMessage(FLog::Channel id, const char* message);
enum GameState
{
UN_INITIALIZED = 0,
IN_GAME,
LEAVE_GAME
};
GameState getGameState()
{
return gameState;
}
void setGameLoaded()
{
gameState = GameState::IN_GAME;
}
void setLeaveGame()
{
gameState = GameState::LEAVE_GAME;
};
private:
GameState gameState;
std::string guid;
static bool handleDebugAssert(const char* expression, const char* filename, int lineNumber);
static bool handleFailure(const char* expression, const char* filename, int lineNumber);
static bool handleG3DFailure(const char* _expression, const std::string& message, const char* filename, int lineNumber,
/*bool& ignoreAlways,*/
bool useGuiPrompt);
static bool handleG3DDebugAssert(const char* _expression, const std::string& message, const char* filename, int lineNumber,
/*bool& ignoreAlways,*/
bool useGuiPrompt);
};
class ThreadLogManager : public LogManager
{
ThreadLogManager();
public:
static ThreadLogManager* getCurrent();
virtual ~ThreadLogManager();
protected:
virtual std::string getLogFileName();
};
#endif

View File

12
client/common/GfxView.hpp Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <QWindow>
#include <QEvent>
#include <QPoint>
class GfxView : public QWindow
{
private:
QPoint lastMousePosition;
QPoint lastMousePositionScaled;
};

View File

@@ -0,0 +1,87 @@
#include "GrayChatBar.hpp"
#define PLACEHOLDER_TEXT "To chat click here or press the \"/\" key"
GrayChatBar::GrayChatBar(QWidget* parent) : QLineEdit(parent)
{
setText(PLACEHOLDER_TEXT);
// note: this uses segoe ui, may not work on linux?
// styles:
// padding-left: 1px
// border-bottom: 5px solid #404040
// background-color: #404040 (#e6e6fa on active)
// color: #ffffc8 (white on active)
// font-weight: bold
// font-family: 'Segoe UI'
// fixed height: 21px
setStyleSheet("QLineEdit { background-color: #404040; color: #ffffc8; font-weight: bold; border-radius: 0 !important; padding: 0 !important; border: none; border-bottom: 5px solid #404040; margin: 0 !important; font-family: 'Segoe UI'; font-size: 12px; padding-left: 1px; }");
setFixedHeight(21);
setMinimumSize(QSize(0, 21));
setVisible(false);
QFont font = this->font();
font.setHintingPreference(QFont::PreferFullHinting); // for crappy aa
setFont(font);
}
void GrayChatBar::focus()
{
setFocus();
}
void GrayChatBar::focusInEvent(QFocusEvent* e)
{
QLineEdit::focusInEvent(e);
setStyleSheet("QLineEdit { background-color: #e6e6fa; color: black; font-weight: bold; border-radius: 0 !important; padding: 0 !important; border: none; border-bottom: 5px solid #404040; margin: 0 !important; font-family: 'Segoe UI'; font-size: 12px; padding-left: 1px; }");
if (text() == PLACEHOLDER_TEXT)
{
clear();
}
}
void GrayChatBar::focusOutEvent(QFocusEvent* e)
{
QLineEdit::focusOutEvent(e);
setStyleSheet("QLineEdit { background-color: #404040; color: #ffffc8; font-weight: bold; border-radius: 0 !important; padding: 0 !important; border: none; border-bottom: 5px solid #404040; margin: 0 !important; font-family: 'Segoe UI'; font-size: 12px; padding-left: 1px; }");
if (text() == "")
{
setText(PLACEHOLDER_TEXT);
}
}
void GrayChatBar::keyPressEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
{
Q_EMIT returnPressed();
handleEnteredText(text());
setText(PLACEHOLDER_TEXT);
clearFocus();
}
else
{
QLineEdit::keyPressEvent(e);
}
}
void GrayChatBar::handleEnteredText(const QString& txt) {
Q_EMIT enteredText(txt);
if (text() == "")
{
setText(PLACEHOLDER_TEXT);
}
}
void GrayChatBar::setVisibility(bool visible)
{
setVisible(visible);
}
void GrayChatBar::mousePressEvent(QMouseEvent* e) {
focus();
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <QLineEdit>
#include <QVBoxLayout>
#include <QKeyEvent>
class GrayChatBar : public QLineEdit
{
Q_OBJECT
public:
GrayChatBar(QWidget* parent = nullptr);
void focus();
protected:
void focusInEvent(QFocusEvent* e) override;
void focusOutEvent(QFocusEvent* e) override;
void keyPressEvent(QKeyEvent* e) override;
void mousePressEvent(QMouseEvent* e) override;
void handleEnteredText(const QString& text);
void setVisibility(bool visible);
Q_SIGNALS:
void returnPressed();
void enteredText(const QString& text);
};

View File

@@ -0,0 +1,668 @@
#include "SDLGameController.hpp"
#include "DataModel/DataModel.hpp"
#include "DataModel/GamepadService.hpp"
#include "DataModel/UserInputService.hpp"
#include "DataModel/ContentProvider.hpp"
#define MAX_AXIS_VALUE 32767.0f
SDLGameController::SDLGameController(shared_ptr<Aya::DataModel> newDM)
{
dataModel = newDM;
initSDL();
}
void SDLGameController::initSDL()
{
if (SDL_Init(SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC) != 0)
{
std::string error = SDL_GetError();
fprintf(stderr, "\nUnable to initialize SDL: %s\n", error.c_str());
return;
}
Aya::ContentId gameControllerDb = Aya::ContentId::fromAssets("fonts/gamecontrollerdb.txt");
std::string filePath = Aya::ContentProvider::findAsset(gameControllerDb);
if (SDL_AddGamepadMappingsFromFile(filePath.c_str()) == -1)
{
std::string error = SDL_GetError();
Aya::StandardOut::singleton()->printf(Aya::MESSAGE_ERROR, "Unable to add SDL controller mappings because %s", error.c_str());
}
if (shared_ptr<Aya::DataModel> sharedDM = dataModel.lock())
{
sharedDM->submitTask(boost::bind(&SDLGameController::bindToDataModel, this), Aya::DataModelJob::Write);
}
}
void SDLGameController::bindToDataModel()
{
if (Aya::UserInputService* inputService = getUserInputService())
{
renderSteppedConnection = inputService->updateInputSignal.connect(boost::bind(&SDLGameController::updateControllers, this));
getSupportedGamepadKeyCodesConnection =
inputService->getSupportedGamepadKeyCodesSignal.connect(boost::bind(&SDLGameController::findAvailableGamepadKeyCodesAndSet, this, _1));
}
if (Aya::HapticService* hapticService = getHapticService())
{
setEnabledVibrationMotorsConnection =
hapticService->setEnabledVibrationMotorsSignal.connect(boost::bind(&SDLGameController::setVibrationMotorsEnabled, this, _1));
setVibrationMotorConnection =
hapticService->setVibrationMotorSignal.connect(boost::bind(&SDLGameController::setVibrationMotor, this, _1, _2, _3));
}
}
SDLGameController::~SDLGameController()
{
renderSteppedConnection.disconnect();
getSupportedGamepadKeyCodesConnection.disconnect();
setEnabledVibrationMotorsConnection.disconnect();
setVibrationMotorConnection.disconnect();
for (boost::unordered_map<int, HapticData>::iterator iter = hapticsFromGamepadId.begin(); iter != hapticsFromGamepadId.end(); ++iter)
{
SDL_Haptic* haptic = iter->second.hapticDevice;
int hapticEffectId = iter->second.hapticEffectId;
SDL_HapticDestroyEffect(haptic, hapticEffectId);
SDL_HapticClose(haptic);
}
hapticsFromGamepadId.clear();
SDL_Quit();
}
Aya::UserInputService* SDLGameController::getUserInputService()
{
if (shared_ptr<Aya::DataModel> sharedDM = dataModel.lock())
{
if (Aya::UserInputService* inputService = Aya::ServiceProvider::create<Aya::UserInputService>(sharedDM.get()))
{
return inputService;
}
}
return NULL;
}
Aya::HapticService* SDLGameController::getHapticService()
{
if (shared_ptr<Aya::DataModel> sharedDM = dataModel.lock())
{
if (Aya::HapticService* hapticService = Aya::ServiceProvider::create<Aya::HapticService>(sharedDM.get()))
{
return hapticService;
}
}
return NULL;
}
Aya::GamepadService* SDLGameController::getGamepadService()
{
if (shared_ptr<Aya::DataModel> sharedDM = dataModel.lock())
{
if (Aya::GamepadService* gamepadService = Aya::ServiceProvider::create<Aya::GamepadService>(sharedDM.get()))
{
return gamepadService;
}
}
return NULL;
}
SDL_Gamepad* SDLGameController::removeControllerMapping(int joystickId)
{
SDL_Gamepad* gameController = NULL;
Aya::UserInputService* inputService = getUserInputService();
if (joystickIdToGamepadId.find(joystickId) != joystickIdToGamepadId.end())
{
int gamepadId = joystickIdToGamepadId[joystickId];
if (gamepadIdToGameController.find(gamepadId) != gamepadIdToGameController.end())
{
gameController = gamepadIdToGameController[gamepadId].second;
gamepadIdToGameController.erase(gamepadId);
if (inputService)
{
inputService->safeFireGamepadDisconnected(Aya::GamepadService::getGamepadEnumForInt(gamepadId));
}
}
if (hapticsFromGamepadId.find(gamepadId) != hapticsFromGamepadId.end())
{
SDL_Haptic* haptic = hapticsFromGamepadId[gamepadId].hapticDevice;
int hapticEffectId = hapticsFromGamepadId[gamepadId].hapticEffectId;
SDL_HapticDestroyEffect(haptic, hapticEffectId);
SDL_HapticClose(haptic);
hapticsFromGamepadId.erase(gamepadId);
}
}
return gameController;
}
void SDLGameController::setupControllerId(int joystickId, int gamepadId, SDL_Gamepad* pad)
{
gamepadIdToGameController[gamepadId] = std::pair<int, SDL_Gamepad*>(joystickId, pad);
joystickIdToGamepadId[joystickId] = gamepadId;
if (Aya::UserInputService* inputService = getUserInputService())
{
inputService->safeFireGamepadConnected(Aya::GamepadService::getGamepadEnumForInt(gamepadId));
}
}
void SDLGameController::addController(int gamepadId)
{
if (SDL_IsGamepad(gamepadId))
{
SDL_Gamepad* pad = SDL_OpenGamepad(gamepadId);
if (pad)
{
SDL_Joystick* joy = SDL_GetGamepadJoystick(pad);
int joystickId = SDL_GetJoystickID(joy);
setupControllerId(joystickId, gamepadId, pad);
}
}
}
void SDLGameController::removeController(int joystickId)
{
if (SDL_Gamepad* pad = removeControllerMapping(joystickId))
{
SDL_CloseGamepad(pad);
}
}
Aya::Gamepad SDLGameController::getRbxGamepadFromJoystickId(int joystickId)
{
if (joystickIdToGamepadId.find(joystickId) != joystickIdToGamepadId.end())
{
if (Aya::GamepadService* gamepadService = getGamepadService())
{
int gamepadId = joystickIdToGamepadId[joystickId];
return gamepadService->getGamepadState(gamepadId);
}
}
return Aya::Gamepad();
}
Aya::KeyCode getKeyCodeFromSDLAxis(SDL_GamepadAxis sdlAxis, int& axisValueChanged)
{
switch (sdlAxis)
{
case SDL_GAMEPAD_AXIS_LEFTX:
axisValueChanged = 0;
return Aya::SDLK_GAMEPAD_THUMBSTICK1;
case SDL_GAMEPAD_AXIS_LEFTY:
axisValueChanged = 1;
return Aya::SDLK_GAMEPAD_THUMBSTICK1;
case SDL_GAMEPAD_AXIS_RIGHTX:
axisValueChanged = 0;
return Aya::SDLK_GAMEPAD_THUMBSTICK2;
case SDL_GAMEPAD_AXIS_RIGHTY:
axisValueChanged = 1;
return Aya::SDLK_GAMEPAD_THUMBSTICK2;
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER:
axisValueChanged = 2;
return Aya::SDLK_GAMEPAD_BUTTONL2;
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER:
axisValueChanged = 2;
return Aya::SDLK_GAMEPAD_BUTTONR2;
case SDL_GAMEPAD_AXIS_INVALID:
case SDL_GAMEPAD_AXIS_MAX:
return Aya::SDLK_UNKNOWN;
}
return Aya::SDLK_UNKNOWN;
}
Aya::KeyCode getKeyCodeFromSDLButton(SDL_GamepadButton sdlButton)
{
switch (sdlButton)
{
case SDL_GAMEPAD_BUTTON_SOUTH:
return Aya::SDLK_GAMEPAD_BUTTONA;
case SDL_GAMEPAD_BUTTON_EAST:
return Aya::SDLK_GAMEPAD_BUTTONB;
case SDL_GAMEPAD_BUTTON_WEST:
return Aya::SDLK_GAMEPAD_BUTTONX;
case SDL_GAMEPAD_BUTTON_NORTH:
return Aya::SDLK_GAMEPAD_BUTTONY;
case SDL_GAMEPAD_BUTTON_START:
return Aya::SDLK_GAMEPAD_BUTTONSTART;
case SDL_GAMEPAD_BUTTON_BACK:
return Aya::SDLK_GAMEPAD_BUTTONSELECT;
case SDL_GAMEPAD_BUTTON_DPAD_UP:
return Aya::SDLK_GAMEPAD_DPADUP;
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
return Aya::SDLK_GAMEPAD_DPADDOWN;
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
return Aya::SDLK_GAMEPAD_DPADLEFT;
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
return Aya::SDLK_GAMEPAD_DPADRIGHT;
case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER:
return Aya::SDLK_GAMEPAD_BUTTONL1;
case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER:
return Aya::SDLK_GAMEPAD_BUTTONR1;
case SDL_GAMEPAD_BUTTON_LEFT_STICK:
return Aya::SDLK_GAMEPAD_BUTTONL3;
case SDL_GAMEPAD_BUTTON_RIGHT_STICK:
return Aya::SDLK_GAMEPAD_BUTTONR3;
case SDL_GAMEPAD_BUTTON_INVALID:
case SDL_GAMEPAD_BUTTON_GUIDE:
case SDL_GAMEPAD_BUTTON_MAX:
return Aya::SDLK_UNKNOWN;
}
return Aya::SDLK_UNKNOWN;
}
bool SDLGameController::setupHapticsForDevice(int id)
{
// already set up
if (hapticsFromGamepadId.find(id) != hapticsFromGamepadId.end())
{
return true;
}
SDL_Haptic* haptic = NULL;
// Open the device
haptic = SDL_HapticOpen(id);
if (haptic)
{
HapticData hapticData;
hapticData.hapticDevice = haptic;
hapticData.hapticEffectId = -1;
hapticData.currentLeftMotorValue = 0.0f;
hapticData.currentRightMotorValue = 0.0f;
hapticsFromGamepadId[id] = hapticData;
return true;
}
return false;
}
void SDLGameController::setVibrationMotorsEnabled(Aya::InputObject::UserInputType gamepadType)
{
int gamepadId = getGamepadIntForEnum(gamepadType);
if (!setupHapticsForDevice(gamepadId))
{
return;
}
SDL_Haptic* haptic = hapticsFromGamepadId[gamepadId].hapticDevice;
if (haptic)
{
if (Aya::HapticService* hapticService = getHapticService())
{
hapticService->setEnabledVibrationMotors(gamepadType, Aya::HapticService::MOTOR_LARGE, true);
hapticService->setEnabledVibrationMotors(gamepadType, Aya::HapticService::MOTOR_SMALL, true);
hapticService->setEnabledVibrationMotors(gamepadType, Aya::HapticService::MOTOR_LEFTTRIGGER, false);
hapticService->setEnabledVibrationMotors(gamepadType, Aya::HapticService::MOTOR_RIGHTTRIGGER, false);
}
}
}
void SDLGameController::setVibrationMotor(
Aya::InputObject::UserInputType gamepadType, Aya::HapticService::VibrationMotor vibrationMotor, shared_ptr<const Aya::Reflection::Tuple> args)
{
int gamepadId = getGamepadIntForEnum(gamepadType);
if (!setupHapticsForDevice(gamepadId))
{
return;
}
float newMotorValue = 0.0f;
Aya::Reflection::Variant newValue = args->values[0];
if (newValue.isFloat())
{
newMotorValue = newValue.get<float>();
newMotorValue = G3D::clamp(newMotorValue, 0.0f, 1.0f);
}
else // no valid number in first position, lets bail
{
Aya::StandardOut::singleton()->printf(
Aya::MESSAGE_ERROR, "First value to HapticService:SetMotor is not a valid number (must be a number between 0-1)");
return;
}
boost::unordered_map<int, HapticData>::iterator iter = hapticsFromGamepadId.find(gamepadId);
// make sure we grab old data so we set the motors that haven't changed value
float leftMotorValue = iter->second.currentLeftMotorValue;
float rightMotorValue = iter->second.currentRightMotorValue;
if (vibrationMotor == Aya::HapticService::MOTOR_LARGE)
{
leftMotorValue = newMotorValue;
}
else if (vibrationMotor == Aya::HapticService::MOTOR_SMALL)
{
rightMotorValue = newMotorValue;
}
SDL_Haptic* haptic = iter->second.hapticDevice;
int oldEffectId = iter->second.hapticEffectId;
if (oldEffectId >= 0)
{
SDL_HapticDestroyEffect(haptic, oldEffectId);
}
if (leftMotorValue <= 0.0f && rightMotorValue <= 0.0f)
{
HapticData hapticData;
hapticData.hapticDevice = haptic;
hapticData.hapticEffectId = -1;
hapticData.currentLeftMotorValue = 0.0f;
hapticData.currentRightMotorValue = 0.0f;
hapticsFromGamepadId[gamepadId] = hapticData;
return;
}
// Create the left/right effect
SDL_HapticEffect effect;
memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default
effect.type = SDL_HAPTIC_LEFTRIGHT;
effect.leftright.large_magnitude = 65535.0f * leftMotorValue;
effect.leftright.small_magnitude = 65535.0f * rightMotorValue;
effect.leftright.length = SDL_HAPTIC_INFINITY;
// Upload the effect
int hapticEffectId = SDL_HapticNewEffect(haptic, &effect);
HapticData hapticData;
hapticData.hapticDevice = haptic;
hapticData.hapticEffectId = hapticEffectId;
hapticData.currentLeftMotorValue = leftMotorValue;
hapticData.currentRightMotorValue = rightMotorValue;
hapticsFromGamepadId[gamepadId] = hapticData;
if (haptic && hapticEffectId >= 0)
{
SDL_HapticRunEffect(haptic, hapticEffectId, SDL_HAPTIC_INFINITY);
}
}
void SDLGameController::refreshHapticEffects()
{
for (boost::unordered_map<int, HapticData>::iterator iter = hapticsFromGamepadId.begin(); iter != hapticsFromGamepadId.end(); ++iter)
{
SDL_Haptic* haptic = iter->second.hapticDevice;
int hapticEffectId = iter->second.hapticEffectId;
if (haptic && hapticEffectId >= 0)
{
SDL_HapticRunEffect(haptic, hapticEffectId, SDL_HAPTIC_INFINITY);
}
}
}
void SDLGameController::onControllerButton(const SDL_GamepadButtonEvent sdlEvent)
{
const Aya::KeyCode buttonCode = getKeyCodeFromSDLButton((SDL_GamepadButton)sdlEvent.button);
if (buttonCode == Aya::SDLK_UNKNOWN)
{
return;
}
Aya::Gamepad gamepad = getRbxGamepadFromJoystickId(sdlEvent.which);
const int buttonState = (sdlEvent.state == SDL_PRESSED) ? 1 : 0;
Aya::InputObject::UserInputState newState = (buttonState == 1) ? Aya::InputObject::INPUT_STATE_BEGIN : Aya::InputObject::INPUT_STATE_END;
if (newState == gamepad[buttonCode]->getUserInputState())
{
return;
}
const G3D::Vector3 lastPos = gamepad[buttonCode]->getPosition();
gamepad[buttonCode]->setPosition(G3D::Vector3(0, 0, buttonState));
gamepad[buttonCode]->setDelta(gamepad[buttonCode]->getPosition() - lastPos);
gamepad[buttonCode]->setInputState(newState);
if (Aya::UserInputService* inputService = getUserInputService())
{
inputService->dangerousFireInputEvent(gamepad[buttonCode], NULL);
}
}
void SDLGameController::onControllerAxis(const SDL_GamepadAxisEvent sdlEvent)
{
int axisValueChanged = -1;
const Aya::KeyCode axisCode = getKeyCodeFromSDLAxis((SDL_GamepadAxis)sdlEvent.axis, axisValueChanged);
if (axisCode == Aya::SDLK_UNKNOWN)
{
return;
}
float axisValue = sdlEvent.value;
axisValue /= MAX_AXIS_VALUE;
axisValue = G3D::clamp(axisValue, -1.0f, 1.0f);
Aya::Gamepad gamepad = getRbxGamepadFromJoystickId(sdlEvent.which);
G3D::Vector3 currentPosition = gamepad[axisCode]->getPosition();
switch (axisValueChanged)
{
case 0:
currentPosition.x = axisValue;
break;
case 1:
currentPosition.y = -axisValue;
break;
case 2:
currentPosition.z = axisValue;
break;
default:
break;
}
G3D::Vector3 lastPos = gamepad[axisCode]->getPosition();
if (lastPos != currentPosition)
{
gamepad[axisCode]->setPosition(currentPosition);
Aya::InputObject::UserInputState currentState = Aya::InputObject::INPUT_STATE_CHANGE;
if (currentPosition == G3D::Vector3::zero())
{
currentState = Aya::InputObject::INPUT_STATE_END;
}
else if (currentPosition.z >= 1.0f)
{
currentState = Aya::InputObject::INPUT_STATE_BEGIN;
}
gamepad[axisCode]->setDelta(currentPosition - lastPos);
gamepad[axisCode]->setInputState(currentState);
if (Aya::UserInputService* inputService = getUserInputService())
{
inputService->dangerousFireInputEvent(gamepad[axisCode], NULL);
}
}
}
void SDLGameController::updateControllers()
{
SDL_Event sdlEvent;
while (SDL_PollEvent(&sdlEvent))
{
switch (sdlEvent.type)
{
case SDL_EVENT_GAMEPAD_ADDED:
addController(sdlEvent.gdevice.which);
break;
case SDL_EVENT_GAMEPAD_REMOVED:
removeController(sdlEvent.gdevice.which);
break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
onControllerButton(sdlEvent.gbutton);
break;
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
onControllerAxis(sdlEvent.gaxis);
break;
default:
break;
}
}
refreshHapticEffects();
}
Aya::KeyCode getKeyCodeFromSDLName(std::string sdlName)
{
if (sdlName.compare("a") == 0)
return Aya::SDLK_GAMEPAD_BUTTONA;
if (sdlName.compare("b") == 0)
return Aya::SDLK_GAMEPAD_BUTTONB;
if (sdlName.compare("x") == 0)
return Aya::SDLK_GAMEPAD_BUTTONX;
if (sdlName.compare("y") == 0)
return Aya::SDLK_GAMEPAD_BUTTONY;
if (sdlName.compare("back") == 0)
return Aya::SDLK_GAMEPAD_BUTTONSELECT;
if (sdlName.compare("start") == 0)
return Aya::SDLK_GAMEPAD_BUTTONSTART;
if (sdlName.compare("dpdown") == 0)
return Aya::SDLK_GAMEPAD_DPADDOWN;
if (sdlName.compare("dpleft") == 0)
return Aya::SDLK_GAMEPAD_DPADLEFT;
if (sdlName.compare("dpright") == 0)
return Aya::SDLK_GAMEPAD_DPADRIGHT;
if (sdlName.compare("dpup") == 0)
return Aya::SDLK_GAMEPAD_DPADUP;
if (sdlName.compare("leftshoulder") == 0)
return Aya::SDLK_GAMEPAD_BUTTONL1;
if (sdlName.compare("lefttrigger") == 0)
return Aya::SDLK_GAMEPAD_BUTTONL2;
if (sdlName.compare("leftstick") == 0)
return Aya::SDLK_GAMEPAD_BUTTONL3;
if (sdlName.compare("rightshoulder") == 0)
return Aya::SDLK_GAMEPAD_BUTTONR1;
if (sdlName.compare("righttrigger") == 0)
return Aya::SDLK_GAMEPAD_BUTTONR2;
if (sdlName.compare("rightstick") == 0)
return Aya::SDLK_GAMEPAD_BUTTONR3;
if (sdlName.compare("leftx") == 0 || sdlName.compare("lefty") == 0)
return Aya::SDLK_GAMEPAD_THUMBSTICK1;
if (sdlName.compare("rightx") == 0 || sdlName.compare("righty") == 0)
return Aya::SDLK_GAMEPAD_THUMBSTICK2;
return Aya::SDLK_UNKNOWN;
}
int SDLGameController::getGamepadIntForEnum(Aya::InputObject::UserInputType gamepadType)
{
switch (gamepadType)
{
case Aya::InputObject::TYPE_GAMEPAD1:
return 0;
case Aya::InputObject::TYPE_GAMEPAD2:
return 1;
case Aya::InputObject::TYPE_GAMEPAD3:
return 2;
case Aya::InputObject::TYPE_GAMEPAD4:
return 3;
default:
break;
}
return -1;
}
void SDLGameController::findAvailableGamepadKeyCodesAndSet(Aya::InputObject::UserInputType gamepadType)
{
shared_ptr<const Aya::Reflection::ValueArray> availableGamepadKeyCodes = getAvailableGamepadKeyCodes(gamepadType);
if (Aya::UserInputService* inputService = getUserInputService())
{
inputService->setSupportedGamepadKeyCodes(gamepadType, availableGamepadKeyCodes);
}
}
shared_ptr<const Aya::Reflection::ValueArray> SDLGameController::getAvailableGamepadKeyCodes(Aya::InputObject::UserInputType gamepadType)
{
int gamepadId = getGamepadIntForEnum(gamepadType);
if (gamepadId < 0 || (gamepadIdToGameController.find(gamepadId) == gamepadIdToGameController.end()))
{
return shared_ptr<const Aya::Reflection::ValueArray>();
}
if (SDL_Gamepad* gameController = gamepadIdToGameController[gamepadId].second)
{
char* mappingStr = SDL_GetGamepadMapping(gameController);
std::string gameControllerMapping(mappingStr ? mappingStr : "");
if (mappingStr) SDL_free(mappingStr);
std::istringstream controllerMappingStream(gameControllerMapping);
std::string mappingItem;
shared_ptr<Aya::Reflection::ValueArray> supportedGamepadFunctions(new Aya::Reflection::ValueArray());
int count = 0;
while (std::getline(controllerMappingStream, mappingItem, ','))
{
// first two settings in mapping are hardware id and device name, don't need those
if (count > 1)
{
std::istringstream mappingStream(mappingItem);
std::string sdlName;
std::getline(mappingStream, sdlName, ':');
// platform is always last thing defined in mappings, don't need it so we are done
if (sdlName.compare("platform") == 0)
{
break;
}
Aya::KeyCode gamepadCode = getKeyCodeFromSDLName(sdlName);
if (gamepadCode != Aya::SDLK_UNKNOWN)
{
supportedGamepadFunctions->push_back(gamepadCode);
}
}
count++;
}
return supportedGamepadFunctions;
}
return shared_ptr<const Aya::Reflection::ValueArray>();
}

View File

@@ -0,0 +1,82 @@
#pragma once
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <boost/weak_ptr.hpp>
#include "SDL3/SDL.h"
#include "SDL3/SDL_gamepad.h"
#include "Utility/KeyCode.hpp"
#include "DataModel/InputObject.hpp"
#include "DataModel/HapticService.hpp"
namespace Aya
{
class DataModel;
class UserInputService;
class GamepadService;
typedef boost::unordered_map<Aya::KeyCode, boost::shared_ptr<Aya::InputObject>> Gamepad;
} // namespace Aya
struct HapticData
{
int hapticEffectId;
float currentLeftMotorValue;
float currentRightMotorValue;
SDL_Haptic* hapticDevice;
};
class SDLGameController
{
private:
boost::weak_ptr<Aya::DataModel> dataModel;
boost::unordered_map<int, std::pair<int, SDL_Gamepad*>> gamepadIdToGameController;
boost::unordered_map<int, HapticData> hapticsFromGamepadId;
boost::unordered_map<int, int> joystickIdToGamepadId;
Aya::signals::scoped_connection renderSteppedConnection;
Aya::signals::scoped_connection getSupportedGamepadKeyCodesConnection;
Aya::signals::scoped_connection setEnabledVibrationMotorsConnection;
Aya::signals::scoped_connection setVibrationMotorConnection;
void initSDL();
Aya::UserInputService* getUserInputService();
Aya::HapticService* getHapticService();
Aya::GamepadService* getGamepadService();
Aya::Gamepad getRbxGamepadFromJoystickId(int joystickId);
void setupControllerId(int joystickId, int gamepadId, SDL_Gamepad* pad);
SDL_Gamepad* removeControllerMapping(int joystickId);
int getGamepadIntForEnum(Aya::InputObject::UserInputType gamepadType);
void findAvailableGamepadKeyCodesAndSet(Aya::InputObject::UserInputType gamepadType);
boost::shared_ptr<const Aya::Reflection::ValueArray> getAvailableGamepadKeyCodes(Aya::InputObject::UserInputType gamepadType);
void bindToDataModel();
// Haptic Functions
void refreshHapticEffects();
bool setupHapticsForDevice(int id);
void setVibrationMotorsEnabled(Aya::InputObject::UserInputType gamepadType);
void setVibrationMotor(Aya::InputObject::UserInputType gamepadType, Aya::HapticService::VibrationMotor vibrationMotor,
shared_ptr<const Aya::Reflection::Tuple> args);
public:
SDLGameController(boost::shared_ptr<Aya::DataModel> newDM);
~SDLGameController();
void updateControllers();
void onControllerAxis(const SDL_GamepadAxisEvent sdlEvent);
void onControllerButton(const SDL_GamepadButtonEvent sdlEvent);
void removeController(int joystickId);
void addController(int gamepadId);
};

View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ChromiumFrame Initialized</title>
<style>
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-weight: 200 900;
src: url("./fonts/SourceSansPro-Regular.ttf") format("ttf");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #111;
color: #fff;
font-family: "Source Sans Pro", sans-serif;
}
.container {
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<p><img src="./textures/Aya.png" width="150" /></p>
<h1>ChromiumFrame Initialized</h1>
<p>Reference the Lua API for instructions on how to use ChromiumFrames.</p>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,323 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4" assettype="animation">
<External>null</External>
<External>nil</External>
<Item class="KeyframeSequence" referent="RBX0">
<Properties>
<bool name="Loop">false</bool>
<string name="Name">Test</string>
<token name="Priority">0</token>
</Properties>
<Item class="Keyframe" referent="RBX1">
<Properties>
<string name="Name">Keyframe</string>
<float name="Time">0</float>
</Properties>
<Item class="Pose" referent="RBX2">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">HumanoidRootPart</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX3">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>0.999999881</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Torso</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX4">
<Properties>
<CoordinateFrame name="CFrame">
<X>5.96046448e-008</X>
<Y>-2.98023224e-008</Y>
<Z>0</Z>
<R00>0.0355361402</R00>
<R01>-0.99936831</R01>
<R02>0</R02>
<R10>0.99936831</R10>
<R11>0.0355361402</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Left Leg</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX5">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>0.819770932</R00>
<R01>-0.57269156</R01>
<R02>0</R02>
<R10>0.57269156</R10>
<R11>0.819770932</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Leg</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX6">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>-2.98023224e-008</Y>
<Z>0</Z>
<R00>0.815004945</R00>
<R01>-0.579453945</R01>
<R02>0</R02>
<R10>0.579453945</R10>
<R11>0.815004945</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Left Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX7">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>2.56113708e-008</Y>
<Z>0</Z>
<R00>0.00526433345</R00>
<R01>-0.999986172</R01>
<R02>0</R02>
<R10>0.999986172</R10>
<R11>0.00526433345</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX8">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>0.999999881</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Head</string>
<float name="Weight">1</float>
</Properties>
</Item>
</Item>
</Item>
</Item>
<Item class="Keyframe" referent="RBX9">
<Properties>
<string name="Name">Keyframe</string>
<float name="Time">1.49062502</float>
</Properties>
<Item class="Pose" referent="RBX10">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">HumanoidRootPart</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX11">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>0.999999881</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Torso</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX12">
<Properties>
<CoordinateFrame name="CFrame">
<X>5.96046448e-008</X>
<Y>-2.98023224e-008</Y>
<Z>0</Z>
<R00>0.0355361402</R00>
<R01>-0.99936831</R01>
<R02>0</R02>
<R10>0.99936831</R10>
<R11>0.0355361402</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Left Leg</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX13">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>0.819770932</R00>
<R01>-0.57269156</R01>
<R02>0</R02>
<R10>0.57269156</R10>
<R11>0.819770932</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Leg</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX14">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>-2.98023224e-008</Y>
<Z>0</Z>
<R00>0.815004945</R00>
<R01>-0.579453945</R01>
<R02>0</R02>
<R10>0.579453945</R10>
<R11>0.815004945</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Left Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX15">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>2.56113708e-008</Y>
<Z>0</Z>
<R00>0.00526433345</R00>
<R01>-0.999986172</R01>
<R02>0</R02>
<R10>0.999986172</R10>
<R11>0.00526433345</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
<Item class="Pose" referent="RBX16">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>0.999999881</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Head</string>
<float name="Weight">1</float>
</Properties>
</Item>
</Item>
</Item>
</Item>
<Item class="Keyframe" referent="RBX17">
<Properties>
<string name="Name">KF1.5</string>
<float name="Time">1.5</float>
</Properties>
</Item>
</Item>
</roblox>

Binary file not shown.

View File

@@ -0,0 +1,203 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4" assettype="animation">
<External>null</External>
<External>nil</External>
<Item class="KeyframeSequence" referent="RBX0">
<Properties>
<bool name="Loop">false</bool>
<string name="Name">Test</string>
<token name="Priority">0</token>
</Properties>
<Item class="Keyframe" referent="RBX1">
<Properties>
<string name="Name">Keyframe</string>
<float name="Time">0</float>
</Properties>
<Item class="Pose" referent="RBX3">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Torso</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX4">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>1.86264515e-009</Y>
<Z>0</Z>
<R00>-0.0374366008</R00>
<R01>-0.99929899</R01>
<R02>0</R02>
<R10>0.99929899</R10>
<R11>-0.0374366008</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
</Item>
</Item>
<Item class="Keyframe" referent="RBX5">
<Properties>
<string name="Name">Keyframe</string>
<float name="Time">0.200000003</float>
</Properties>
<Item class="Pose" referent="RBX6">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Torso</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX7">
<Properties>
<CoordinateFrame name="CFrame">
<X>3.25962901e-009</X>
<Y>-5.96046448e-008</Y>
<Z>0</Z>
<R00>0.999995768</R00>
<R01>-0.00290136319</R01>
<R02>0</R02>
<R10>0.00290136319</R10>
<R11>0.999995768</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
</Item>
</Item>
<Item class="Keyframe" referent="RBX8">
<Properties>
<string name="Name">Keyframe</string>
<float name="Time">0.300000012</float>
</Properties>
<Item class="Pose" referent="RBX9">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Torso</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX10">
<Properties>
<CoordinateFrame name="CFrame">
<X>3.25962901e-009</X>
<Y>-5.96046448e-008</Y>
<Z>0</Z>
<R00>0.999995768</R00>
<R01>-0.00290136319</R01>
<R02>0</R02>
<R10>0.00290136319</R10>
<R11>0.999995768</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
</Item>
</Item>
<Item class="Keyframe" referent="RBX11">
<Properties>
<string name="Name">Keyframe</string>
<float name="Time">0.5</float>
</Properties>
<Item class="Pose" referent="RBX12">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Torso</string>
<float name="Weight">1</float>
</Properties>
<Item class="Pose" referent="RBX13">
<Properties>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>1.86264515e-009</Y>
<Z>0</Z>
<R00>-0.0374366008</R00>
<R01>-0.99929899</R01>
<R02>0</R02>
<R10>0.99929899</R10>
<R11>-0.0374366008</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="MaskWeight">0</float>
<string name="Name">Right Arm</string>
<float name="Weight">1</float>
</Properties>
</Item>
</Item>
</Item>
</Item>
</roblox>

Binary file not shown.

View File

@@ -0,0 +1,606 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4">
<External>null</External>
<External>nil</External>
<Item class="Model" referent="RBX0">
<Properties>
<token name="Controller">7</token>
<bool name="ControllerFlagShown">true</bool>
<CoordinateFrame name="ModelInPrimary">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<string name="Name">erik.cassel</string>
<Ref name="PrimaryPart">RBX1</Ref>
<bool name="archivable">true</bool>
</Properties>
<Item class="Part" referent="RBX1">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">4</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">24</int>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>4.5</Y>
<Z>25.5</Z>
<R00>-1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>-1</R22>
</CoordinateFrame>
<bool name="CanCollide">true</bool>
<token name="Controller">0</token>
<bool name="ControllerFlagShown">true</bool>
<bool name="DraggingV1">false</bool>
<float name="Elasticity">0.5</float>
<token name="FormFactor">0</token>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">-0.5</float>
<float name="LeftParamB">0.5</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<string name="Name">Head</string>
<float name="Reflectance">0</float>
<float name="RightParamA">-0.5</float>
<float name="RightParamB">0.5</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">0</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
<token name="shape">1</token>
<Vector3 name="size">
<X>2</X>
<Y>1</Y>
<Z>1</Z>
</Vector3>
</Properties>
<Item class="SpecialMesh" referent="RBX2">
<Properties>
<Content name="MeshId">
<null></null>
</Content>
<token name="MeshType">0</token>
<string name="Name">Mesh</string>
<Vector3 name="Scale">
<X>1.25</X>
<Y>1.25</Y>
<Z>1.25</Z>
</Vector3>
<Content name="TextureId">
<null></null>
</Content>
<Vector3 name="VertexColor">
<X>1</X>
<Y>1</Y>
<Z>1</Z>
</Vector3>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Decal" referent="RBX3">
<Properties>
<token name="Face">5</token>
<string name="Name">face</string>
<float name="Shiny">20</float>
<float name="Specular">0</float>
<Content name="Texture">
<url>ayaasset://textures/face.png</url>
</Content>
<bool name="archivable">true</bool>
</Properties>
</Item>
</Item>
<Item class="Part" referent="RBX4">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">4</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">23</int>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>3</Y>
<Z>25.5</Z>
<R00>-1</R00>
<R01>0</R01>
<R02>-0</R02>
<R10>-0</R10>
<R11>1</R11>
<R12>-0</R12>
<R20>-0</R20>
<R21>0</R21>
<R22>-1</R22>
</CoordinateFrame>
<bool name="CanCollide">true</bool>
<token name="Controller">0</token>
<bool name="ControllerFlagShown">true</bool>
<bool name="DraggingV1">false</bool>
<float name="Elasticity">0.5</float>
<token name="FormFactor">0</token>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">0</float>
<float name="LeftParamB">0</float>
<token name="LeftSurface">2</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<string name="Name">Torso</string>
<float name="Reflectance">0</float>
<float name="RightParamA">0</float>
<float name="RightParamB">0</float>
<token name="RightSurface">2</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">3</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
<token name="shape">1</token>
<Vector3 name="size">
<X>2</X>
<Y>2</Y>
<Z>1</Z>
</Vector3>
</Properties>
<Item class="Decal" referent="RBX5">
<Properties>
<token name="Face">5</token>
<string name="Name">roblox</string>
<float name="Shiny">20</float>
<float name="Specular">0</float>
<Content name="Texture">
<null></null>
</Content>
<bool name="archivable">true</bool>
</Properties>
</Item>
</Item>
<Item class="Part" referent="RBX6">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">4</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">24</int>
<CoordinateFrame name="CFrame">
<X>1.5</X>
<Y>3</Y>
<Z>25.5</Z>
<R00>-1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>-1</R22>
</CoordinateFrame>
<bool name="CanCollide">false</bool>
<token name="Controller">0</token>
<bool name="ControllerFlagShown">true</bool>
<bool name="DraggingV1">false</bool>
<float name="Elasticity">0.5</float>
<token name="FormFactor">0</token>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">-0.5</float>
<float name="LeftParamB">0.5</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<string name="Name">Left Arm</string>
<float name="Reflectance">0</float>
<float name="RightParamA">-0.5</float>
<float name="RightParamB">0.5</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">3</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
<token name="shape">1</token>
<Vector3 name="size">
<X>1</X>
<Y>2</Y>
<Z>1</Z>
</Vector3>
</Properties>
</Item>
<Item class="Part" referent="RBX7">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">4</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">24</int>
<CoordinateFrame name="CFrame">
<X>-1.5</X>
<Y>3</Y>
<Z>25.5</Z>
<R00>-1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>-1</R22>
</CoordinateFrame>
<bool name="CanCollide">false</bool>
<token name="Controller">0</token>
<bool name="ControllerFlagShown">true</bool>
<bool name="DraggingV1">false</bool>
<float name="Elasticity">0.5</float>
<token name="FormFactor">0</token>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">-0.5</float>
<float name="LeftParamB">0.5</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<string name="Name">Right Arm</string>
<float name="Reflectance">0</float>
<float name="RightParamA">-0.5</float>
<float name="RightParamB">0.5</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">3</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
<token name="shape">1</token>
<Vector3 name="size">
<X>1</X>
<Y>2</Y>
<Z>1</Z>
</Vector3>
</Properties>
</Item>
<Item class="Part" referent="RBX8">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">0</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">119</int>
<CoordinateFrame name="CFrame">
<X>0.5</X>
<Y>1</Y>
<Z>25.5</Z>
<R00>-1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>-1</R22>
</CoordinateFrame>
<bool name="CanCollide">false</bool>
<token name="Controller">0</token>
<bool name="ControllerFlagShown">true</bool>
<bool name="DraggingV1">false</bool>
<float name="Elasticity">0.5</float>
<token name="FormFactor">0</token>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">-0.5</float>
<float name="LeftParamB">0.5</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<string name="Name">Left Leg</string>
<float name="Reflectance">0</float>
<float name="RightParamA">-0.5</float>
<float name="RightParamB">0.5</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">3</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
<token name="shape">1</token>
<Vector3 name="size">
<X>1</X>
<Y>2</Y>
<Z>1</Z>
</Vector3>
</Properties>
</Item>
<Item class="Part" referent="RBX9">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">0</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">119</int>
<CoordinateFrame name="CFrame">
<X>-0.5</X>
<Y>1</Y>
<Z>25.5</Z>
<R00>-1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>-1</R22>
</CoordinateFrame>
<bool name="CanCollide">false</bool>
<token name="Controller">0</token>
<bool name="ControllerFlagShown">true</bool>
<bool name="DraggingV1">false</bool>
<float name="Elasticity">0.5</float>
<token name="FormFactor">0</token>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">-0.5</float>
<float name="LeftParamB">0.5</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<string name="Name">Right Leg</string>
<float name="Reflectance">0</float>
<float name="RightParamA">-0.5</float>
<float name="RightParamB">0.5</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">3</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
<token name="shape">1</token>
<Vector3 name="size">
<X>1</X>
<Y>2</Y>
<Z>1</Z>
</Vector3>
</Properties>
</Item>
<Item class="Humanoid" referent="RBX10">
<Properties>
<float name="Health">100</float>
<bool name="Jump">false</bool>
<float name="MaxHealth">100</float>
<string name="Name">Humanoid</string>
<bool name="Sit">false</bool>
<Vector3 name="TargetPoint">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<Vector3 name="WalkDirection">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="WalkRotationalVelocity">0</float>
<Ref name="WalkToPart">null</Ref>
<Vector3 name="WalkToPoint">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Part" referent="RBX11">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">0</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">23</int>
<CoordinateFrame name="CFrame">
<X>0</X>
<Y>3</Y>
<Z>25.5</Z>
<R00>-1</R00>
<R01>0</R01>
<R02>-0</R02>
<R10>-0</R10>
<R11>1</R11>
<R12>-0</R12>
<R20>-0</R20>
<R21>0</R21>
<R22>-1</R22>
</CoordinateFrame>
<bool name="CanCollide">false</bool>
<token name="Controller">0</token>
<bool name="ControllerFlagShown">true</bool>
<bool name="DraggingV1">false</bool>
<float name="Elasticity">0.5</float>
<token name="FormFactor">0</token>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">0</float>
<float name="LeftParamB">0</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<string name="Name">HumanoidRootPart</string>
<float name="Reflectance">0</float>
<float name="RightParamA">0</float>
<float name="RightParamB">0</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">0</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">1</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<bool name="archivable">true</bool>
<token name="shape">1</token>
<Vector3 name="size">
<X>2</X>
<Y>2</Y>
<Z>1</Z>
</Vector3>
</Properties>
</Item>
</Item>
</roblox>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4">
<External>null</External>
<External>nil</External>
<Item class="Script" referent="RBX0">
<Properties>
<bool name="Disabled">true</bool>
<Content name="LinkedSource"><null></null></Content>
<string name="Name">ReenableDialogScript</string>
<ProtectedString name="Source">wait(5)
local dialog = script.Parent
if dialog:IsA(&quot;Dialog&quot;) then
dialog.InUse = false
end
script:Remove()
</ProtectedString>
<bool name="archivable">true</bool>
</Properties>
</Item>
<Item class="Script" referent="RBX1">
<Properties>
<bool name="Disabled">true</bool>
<Content name="LinkedSource"><null></null></Content>
<string name="Name">TimeoutScript</string>
<ProtectedString name="Source">wait(15)
local dialog = script.Parent
if dialog:IsA(&quot;Dialog&quot;) then
dialog.InUse = false
end
script:Remove()
</ProtectedString>
<bool name="archivable">true</bool>
</Properties>
</Item>
</roblox>

View File

@@ -0,0 +1,689 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4">
<External>null</External>
<External>nil</External>
<Item class="LocalScript" referent="RBXC49238CC391A40B0B08D3C0989F85A53">
<Properties>
<bool name="Disabled">false</bool>
<Content name="LinkedSource">
<null></null>
</Content>
<string name="Name">Animate</string>
<ProtectedString name="Source"><![CDATA[function waitForChild(parent, childName)
local child = parent:findFirstChild(childName)
if child then return child end
while true do
child = parent.ChildAdded:wait()
if child.Name==childName then return child end
end
end
local Figure = script.Parent
local Torso = waitForChild(Figure, "Torso")
local RightShoulder = waitForChild(Torso, "Right Shoulder")
local LeftShoulder = waitForChild(Torso, "Left Shoulder")
local RightHip = waitForChild(Torso, "Right Hip")
local LeftHip = waitForChild(Torso, "Left Hip")
local Neck = waitForChild(Torso, "Neck")
local Humanoid = waitForChild(Figure, "Humanoid")
local pose = "Standing"
local currentAnim = ""
local currentAnimInstance = nil
local currentAnimTrack = nil
local currentAnimKeyframeHandler = nil
local currentAnimSpeed = 1.0
local animTable = {}
local animNames = {
idle = {
{ id = "ayaasset://avatar/animations/idle0.rbxm", weight = 9 },
{ id = "ayaasset://avatar/animations/idle1.rbxm", weight = 1 }
},
walk = {
{ id = "ayaasset://avatar/animations/walk.rbxm", weight = 10 }
},
run = {
{ id = "ayaasset://avatar/animations/walk.rbxm", weight = 10 }
},
jump = {
{ id = "ayaasset://avatar/animations/jump.rbxm", weight = 10 }
},
fall = {
{ id = "ayaasset://avatar/animations/fall.rbxm", weight = 10 }
},
climb = {
{ id = "ayaasset://avatar/animations/climb.rbxm", weight = 10 }
},
sit = {
{ id = "ayaasset://avatar/animations/sit.rbxm", weight = 10 }
},
toolnone = {
{ id = "ayaasset://avatar/animations/toolnone.rbxm", weight = 10 }
},
toolslash = {
{ id = "ayaasset://avatar/animations/toolslash.rbxm", weight = 10 }
},
toollunge = {
{ id = "ayaasset://avatar/animations/toollunge.rbxm", weight = 10 }
},
wave = {
{ id = "ayaasset://avatar/animations/emotes/wave.rbxm", weight = 10 }
},
point = {
{ id = "ayaasset://avatar/animations/emotes/point.rbxm", weight = 10 }
},
dance1 = {
{ id = "ayaasset://avatar/animations/emotes/dance1_0.rbxm", weight = 10 },
{ id = "ayaasset://avatar/animations/emotes/dance1_1.rbxm", weight = 10 },
{ id = "ayaasset://avatar/animations/emotes/dance1_2.rbxm", weight = 10 }
},
dance2 = {
{ id = "ayaasset://avatar/animations/emotes/dance2_0.rbxm", weight = 10 },
{ id = "ayaasset://avatar/animations/emotes/dance2_1.rbxm", weight = 10 },
{ id = "ayaasset://avatar/animations/emotes/dance2_2.rbxm", weight = 10 }
},
dance3 = {
{ id = "ayaasset://avatar/animations/emotes/dance3_0.rbxm", weight = 10 },
{ id = "ayaasset://avatar/animations/emotes/dance3_1.rbxm", weight = 10 },
{ id = "ayaasset://avatar/animations/emotes/dance3_2.rbxm", weight = 10 }
},
laugh = {
{ id = "ayaasset://avatar/animations/emotes/laugh.rbxm", weight = 10 }
},
cheer = {
{ id = "ayaasset://avatar/animations/emotes/cheer.rbxm", weight = 10 }
},
}
local dances = {"dance1", "dance2", "dance3"}
-- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
local emoteNames = { wave = false, point = false, dance1 = true, dance2 = true, dance3 = true, laugh = false, cheer = false}
function configureAnimationSet(name, fileList)
if (animTable[name] ~= nil) then
for _, connection in pairs(animTable[name].connections) do
connection:disconnect()
end
end
animTable[name] = {}
animTable[name].count = 0
animTable[name].totalWeight = 0
animTable[name].connections = {}
-- check for config values
local config = script:FindFirstChild(name)
if (config ~= nil) then
-- print("Loading anims " .. name)
table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
local idx = 1
for _, childPart in pairs(config:GetChildren()) do
if (childPart:IsA("Animation")) then
table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
animTable[name][idx] = {}
animTable[name][idx].anim = childPart
local weightObject = childPart:FindFirstChild("Weight")
if (weightObject == nil) then
animTable[name][idx].weight = 1
else
animTable[name][idx].weight = weightObject.Value
end
animTable[name].count = animTable[name].count + 1
animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
-- print(name .. " [" .. idx .. "] " .. animTable[name][idx].anim.AnimationId .. " (" .. animTable[name][idx].weight .. ")")
idx = idx + 1
end
end
end
-- fallback to defaults
if (animTable[name].count <= 0) then
for idx, anim in pairs(fileList) do
animTable[name][idx] = {}
animTable[name][idx].anim = Instance.new("Animation")
animTable[name][idx].anim.Name = name
animTable[name][idx].anim.AnimationId = anim.id
animTable[name][idx].weight = anim.weight
animTable[name].count = animTable[name].count + 1
animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
-- print(name .. " [" .. idx .. "] " .. anim.id .. " (" .. anim.weight .. ")")
end
end
end
-- Setup animation objects
function scriptChildModified(child)
local fileList = animNames[child.Name]
if (fileList ~= nil) then
configureAnimationSet(child.Name, fileList)
end
end
script.ChildAdded:connect(scriptChildModified)
script.ChildRemoved:connect(scriptChildModified)
for name, fileList in pairs(animNames) do
configureAnimationSet(name, fileList)
end
-- ANIMATION
-- declarations
local toolAnim = "None"
local toolAnimTime = 0
local jumpAnimTime = 0
local jumpAnimDuration = 0.3
local toolTransitionTime = 0.1
local fallTransitionTime = 0.3
local jumpMaxLimbVelocity = 0.75
-- functions
function stopAllAnimations()
local oldAnim = currentAnim
-- return to idle if finishing an emote
if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
oldAnim = "idle"
end
currentAnim = ""
currentAnimInstance = nil
if (currentAnimKeyframeHandler ~= nil) then
currentAnimKeyframeHandler:disconnect()
end
if (currentAnimTrack ~= nil) then
currentAnimTrack:Stop()
currentAnimTrack:Destroy()
currentAnimTrack = nil
end
return oldAnim
end
function setAnimationSpeed(speed)
if speed ~= currentAnimSpeed then
currentAnimSpeed = speed
currentAnimTrack:AdjustSpeed(currentAnimSpeed)
end
end
function keyFrameReachedFunc(frameName)
if (frameName == "End") then
local repeatAnim = currentAnim
-- return to idle if finishing an emote
if (emoteNames[repeatAnim] ~= nil and emoteNames[repeatAnim] == false) then
repeatAnim = "idle"
end
local animSpeed = currentAnimSpeed
playAnimation(repeatAnim, 0.0, Humanoid)
setAnimationSpeed(animSpeed)
end
end
-- Preload animations
function playAnimation(animName, transitionTime, humanoid)
local roll = math.random(1, animTable[animName].totalWeight)
local origRoll = roll
local idx = 1
while (roll > animTable[animName][idx].weight) do
roll = roll - animTable[animName][idx].weight
idx = idx + 1
end
-- print(animName .. " " .. idx .. " [" .. origRoll .. "]")
local anim = animTable[animName][idx].anim
-- switch animation
if (anim ~= currentAnimInstance) then
if (currentAnimTrack ~= nil) then
currentAnimTrack:Stop(transitionTime)
currentAnimTrack:Destroy()
end
currentAnimSpeed = 1.0
-- load it to the humanoid; get AnimationTrack
currentAnimTrack = humanoid:LoadAnimation(anim)
-- play the animation
currentAnimTrack:Play(transitionTime)
currentAnim = animName
currentAnimInstance = anim
-- set up keyframe name triggers
if (currentAnimKeyframeHandler ~= nil) then
currentAnimKeyframeHandler:disconnect()
end
currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
end
end
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
local toolAnimName = ""
local toolAnimTrack = nil
local toolAnimInstance = nil
local currentToolAnimKeyframeHandler = nil
function toolKeyFrameReachedFunc(frameName)
if (frameName == "End") then
-- print("Keyframe : ".. frameName)
playToolAnimation(toolAnimName, 0.0, Humanoid)
end
end
function playToolAnimation(animName, transitionTime, humanoid)
local roll = math.random(1, animTable[animName].totalWeight)
local origRoll = roll
local idx = 1
while (roll > animTable[animName][idx].weight) do
roll = roll - animTable[animName][idx].weight
idx = idx + 1
end
-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]")
local anim = animTable[animName][idx].anim
if (toolAnimInstance ~= anim) then
if (toolAnimTrack ~= nil) then
toolAnimTrack:Stop()
toolAnimTrack:Destroy()
transitionTime = 0
end
-- load it to the humanoid; get AnimationTrack
toolAnimTrack = humanoid:LoadAnimation(anim)
-- play the animation
toolAnimTrack:Play(transitionTime)
toolAnimName = animName
toolAnimInstance = anim
currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
end
end
function stopToolAnimations()
local oldAnim = toolAnimName
if (currentToolAnimKeyframeHandler ~= nil) then
currentToolAnimKeyframeHandler:disconnect()
end
toolAnimName = ""
toolAnimInstance = nil
if (toolAnimTrack ~= nil) then
toolAnimTrack:Stop()
toolAnimTrack:Destroy()
toolAnimTrack = nil
end
return oldAnim
end
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
function onRunning(speed)
if speed>0.01 then
playAnimation("walk", 0.1, Humanoid)
if currentAnimInstance and currentAnimInstance.AnimationId == "ayaasset://avatar/animations/walk.rbxm" then
setAnimationSpeed(speed / 14.5)
end
pose = "Running"
else
playAnimation("idle", 0.1, Humanoid)
pose = "Standing"
end
end
function onDied()
pose = "Dead"
end
function onJumping()
playAnimation("jump", 0.1, Humanoid)
jumpAnimTime = jumpAnimDuration
pose = "Jumping"
end
function onClimbing(speed)
playAnimation("climb", 0.1, Humanoid)
setAnimationSpeed(speed / 12.0)
pose = "Climbing"
end
function onGettingUp()
pose = "GettingUp"
end
function onFreeFall()
if (jumpAnimTime <= 0) then
playAnimation("fall", fallTransitionTime, Humanoid)
end
pose = "FreeFall"
end
function onFallingDown()
pose = "FallingDown"
end
function onSeated()
pose = "Seated"
end
function onPlatformStanding()
pose = "PlatformStanding"
end
function onSwimming(speed)
if speed>0 then
pose = "Running"
else
pose = "Standing"
end
end
function getTool()
for _, kid in ipairs(Figure:GetChildren()) do
if kid.className == "Tool" then return kid end
end
return nil
end
function getToolAnim(tool)
for _, c in ipairs(tool:GetChildren()) do
if c.Name == "toolanim" and c.className == "StringValue" then
return c
end
end
return nil
end
function animateTool()
if (toolAnim == "None") then
playToolAnimation("toolnone", toolTransitionTime, Humanoid)
return
end
if (toolAnim == "Slash") then
playToolAnimation("toolslash", 0, Humanoid)
return
end
if (toolAnim == "Lunge") then
playToolAnimation("toollunge", 0, Humanoid)
return
end
end
function moveSit()
RightShoulder.MaxVelocity = 0.15
LeftShoulder.MaxVelocity = 0.15
RightShoulder:SetDesiredAngle(3.14 /2)
LeftShoulder:SetDesiredAngle(-3.14 /2)
RightHip:SetDesiredAngle(3.14 /2)
LeftHip:SetDesiredAngle(-3.14 /2)
end
local lastTick = 0
function move(time)
local amplitude = 1
local frequency = 1
local deltaTime = time - lastTick
lastTick = time
local climbFudge = 0
local setAngles = false
if (jumpAnimTime > 0) then
jumpAnimTime = jumpAnimTime - deltaTime
end
if (pose == "FreeFall" and jumpAnimTime <= 0) then
playAnimation("fall", fallTransitionTime, Humanoid)
elseif (pose == "Seated") then
playAnimation("sit", 0.5, Humanoid)
return
elseif (pose == "Running") then
playAnimation("walk", 0.1, Humanoid)
elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
-- print("Wha " .. pose)
stopAllAnimations()
amplitude = 0.1
frequency = 1
setAngles = true
end
if (setAngles) then
desiredAngle = amplitude * math.sin(time * frequency)
RightShoulder:SetDesiredAngle(desiredAngle + climbFudge)
LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge)
RightHip:SetDesiredAngle(-desiredAngle)
LeftHip:SetDesiredAngle(-desiredAngle)
end
-- Tool Animation handling
local tool = getTool()
if tool and tool:FindFirstChild("Handle") then
animStringValueObject = getToolAnim(tool)
if animStringValueObject then
toolAnim = animStringValueObject.Value
-- message recieved, delete StringValue
animStringValueObject.Parent = nil
toolAnimTime = time + .3
end
if time > toolAnimTime then
toolAnimTime = 0
toolAnim = "None"
end
animateTool()
else
stopToolAnimations()
toolAnim = "None"
toolAnimInstance = nil
toolAnimTime = 0
end
end
-- connect events
Humanoid.Died:connect(onDied)
Humanoid.Running:connect(onRunning)
Humanoid.Jumping:connect(onJumping)
Humanoid.Climbing:connect(onClimbing)
Humanoid.GettingUp:connect(onGettingUp)
Humanoid.FreeFalling:connect(onFreeFall)
Humanoid.FallingDown:connect(onFallingDown)
Humanoid.Seated:connect(onSeated)
Humanoid.PlatformStanding:connect(onPlatformStanding)
Humanoid.Swimming:connect(onSwimming)
-- setup emote chat hook
game.Players.LocalPlayer.Chatted:connect(function(msg)
local emote = ""
if msg == "/e dance" then
emote = dances[math.random(1, #dances)]
elseif (string.sub(msg, 1, 3) == "/e ") then
emote = string.sub(msg, 4)
elseif (string.sub(msg, 1, 7) == "/emote ") then
emote = string.sub(msg, 8)
end
if (pose == "Standing" and emoteNames[emote] ~= nil) then
playAnimation(emote, 0.1, Humanoid)
end
end)
-- main program
local runService = game:service("RunService");
-- initialize to idle
playAnimation("idle", 0.1, Humanoid)
pose = "Standing"
while Figure.Parent~=nil do
local _, time = wait(0.1)
move(time)
end
]]> </ProtectedString>
</Properties>
<Item class="StringValue" referent="RBX3D115054235C475E9E23460AF948BD6F">
<Properties>
<string name="Name">idle</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBXDB67065FB85E4931999CB515B5F2012A">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/idle0.rbxm</url>
</Content>
<string name="Name">Animation1</string>
</Properties>
<Item class="NumberValue" referent="RBX9C1D89D976924979BDD8B81DA97BE114">
<Properties>
<string name="Name">Weight</string>
<double name="Value">9</double>
</Properties>
</Item>
</Item>
<Item class="Animation" referent="RBXEEE171AA4C1C4802A98EA849C0B0A8AC">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/idle1.rbxm</url>
</Content>
<string name="Name">Animation2</string>
</Properties>
<Item class="NumberValue" referent="RBX37B140D9414C4473A5F27F7880B0EC4E">
<Properties>
<string name="Name">Weight</string>
<double name="Value">1</double>
</Properties>
</Item>
</Item>
</Item>
<Item class="StringValue" referent="RBX6B0595F7D6464E039C6C20310AF91669">
<Properties>
<string name="Name">walk</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBX45D6152C54FA4EF7B0F9CBF069550557">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/walk.rbxm</url>
</Content>
<string name="Name">WalkAnim</string>
</Properties>
</Item>
</Item>
<Item class="StringValue" referent="RBX304A801B2F904AA59F892145C3DA51F4">
<Properties>
<string name="Name">run</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBXA37336981B6E454C90E45A7F01515966">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/walk.rbxm</url>
</Content>
<string name="Name">RunAnim</string>
</Properties>
</Item>
</Item>
<Item class="StringValue" referent="RBX992310CD075D4083AA3FC397200F0E12">
<Properties>
<string name="Name">jump</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBXDB0FB6EAF0A94640AD7C222F7E4E39F4">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/jump.rbxm</url>
</Content>
<string name="Name">JumpAnim</string>
</Properties>
</Item>
</Item>
<Item class="StringValue" referent="RBXE784B068E17041EDBE1C80F73A8FB305">
<Properties>
<string name="Name">climb</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBX94C1F5C954294A889B341487BAC89356">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/climb.rbxm</url>
</Content>
<string name="Name">ClimbAnim</string>
</Properties>
</Item>
</Item>
<Item class="StringValue" referent="RBX40FB7BAC1B514D918FD0D59D70A13401">
<Properties>
<string name="Name">toolnone</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBX6B27C35810754C93915CA4FE34E8EB95">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/toolnone.rbxm</url>
</Content>
<string name="Name">ToolNoneAnim</string>
</Properties>
</Item>
</Item>
<Item class="StringValue" referent="RBX9D56FC8B85B240089A73C4C0BF994681">
<Properties>
<string name="Name">fall</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBX0766704DC00944A88D7F0204B7AD2177">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/fall.rbxm</url>
</Content>
<string name="Name">FallAnim</string>
</Properties>
</Item>
</Item>
<Item class="StringValue" referent="RBXCE77F4BD43F74ECE8CEC4CB497927D27">
<Properties>
<string name="Name">sit</string>
<string name="Value"></string>
</Properties>
<Item class="Animation" referent="RBXBEBAA19B49FE45FB9D852B2290377C2C">
<Properties>
<Content name="AnimationId">
<url>ayaasset://avatar/animations/sit.rbxm</url>
</Content>
<string name="Name">SitAnim</string>
</Properties>
</Item>
</Item>
</Item>
</roblox>

View File

@@ -0,0 +1,466 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4">
<External>null</External>
<External>nil</External>
<Item class="Script" referent="RBX440EE2113E074565A1C69E447652B15D">
<Properties>
<bool name="Disabled">false</bool>
<Content name="LinkedSource">
<null></null>
</Content>
<string name="Name">Sound</string>
<ProtectedString name="Source"><![CDATA[---This server script creates the sounds and also exists so that it can be easily copied into an NPC and create sounds for that NPC.
--Remove the local script if you copy this into an NPC.
function waitForChild(parent, childName)
local child = parent:findFirstChild(childName)
if child then return child end
while true do
child = parent.ChildAdded:wait()
if child.Name==childName then return child end
end
end
function newSound(name, id)
local sound = Instance.new("Sound")
sound.SoundId = id
sound.Name = name
sound.archivable = false
sound.Parent = script.Parent.Head
return sound
end
-- declarations
local sGettingUp = newSound("GettingUp", "ayaasset://sounds/action_get_up.mp3")
local sDied = newSound("Died", "ayaasset://sounds/uuhhh.mp3")
local sFreeFalling = newSound("FreeFalling", "ayaasset://sounds/action_falling.mp3")
local sJumping = newSound("Jumping", "ayaasset://sounds/action_jump.mp3")
local sLanding = newSound("Landing", "ayaasset://sounds/action_jump_land.mp3")
local sSplash = newSound("Splash", "ayaasset://sounds/impact_water.mp3")
local sRunning = newSound("Running", "ayaasset://sounds/action_footsteps_plastic.mp3")
sRunning.Looped = true
local sSwimming = newSound("Swimming", "ayaasset://sounds/action_swim.mp3")
sSwimming.Looped = true
local sClimbing = newSound("Climbing", "ayaasset://sounds/action_footsteps_plastic.mp3")
sClimbing.Looped = true
local classic_sFallingDown = newSound("classic_FallingDown", "ayaasset://sounds/splat.mp3")
local classic_sFreeFalling = newSound("classic_FreeFalling", "ayaasset://sounds/swoosh.mp3")
local classic_sGettingUp = newSound("classic_GettingUp", "ayaasset://sounds/hit.mp3")
local classic_sJumping = newSound("classic_Jumping", "ayaasset://sounds/button.mp3")
local classic_sRunning = newSound("classic_Running", "ayaasset://sounds/bfsl-minifigfoots1.mp3")
classic_sRunning.Looped = true
local GameSettings = UserSettings().GameSettings
local useClassicSounds = GameSettings.VirtualVersion == Enum.VirtualVersion['2012'] or GameSettings.VirtualVersion == Enum.VirtualVersion['2013']
local Figure = script.Parent
local Head = waitForChild(Figure, "Head")
local Humanoid = waitForChild(Figure, "Humanoid")
local hasPlayer = game.Players:GetPlayerFromCharacter(script.Parent)
local filteringEnabled = game.Workspace.FilteringEnabled
local prevState = "None"
-- functions
function onDied()
stopLoopedSounds()
sDied:Play()
end
local fallCount = 0
local fallSpeed = 0
function onStateFall(state, sound)
fallCount = fallCount + 1
if state then
sound.Volume = 0
sound:Play()
Spawn( function()
local t = 0
local thisFall = fallCount
while t < 1.5 and fallCount == thisFall do
local vol = math.max(t - 0.3 , 0)
sound.Volume = vol
wait(0.1)
t = t + 0.1
end
end)
else
sound:Stop()
end
fallSpeed = math.max(fallSpeed, math.abs(Head.Velocity.Y))
end
function onStateNoStop(state, sound)
if state then
sound:Play()
end
end
function onRunning(speed)
if useClassicSounds then
if speed > 0.01 then
classic_sRunning:Play()
else
classic_sRunning:Pause()
end
return
end
sClimbing:Stop()
sSwimming:Stop()
if (prevState == "FreeFall" and fallSpeed > 0.1) then
local vol = math.min(1.0, math.max(0.0, (fallSpeed - 50) / 110))
sLanding.Volume = vol
sLanding:Play()
fallSpeed = 0
end
if speed>0.5 then
sRunning:Play()
sRunning.Pitch = speed / 8.0
else
sRunning:Stop()
end
prevState = "Run"
end
function onSwimming(speed)
if (prevState ~= "Swim" and speed > 0.1) then
local volume = math.min(1.0, speed / 350)
sSplash.Volume = volume
sSplash:Play()
prevState = "Swim"
end
sClimbing:Stop()
sRunning:Stop()
sSwimming.Pitch = 1.6
sSwimming:Play()
end
function onClimbing(speed)
sRunning:Stop()
sSwimming:Stop()
if speed>0.01 then
sClimbing:Play()
sClimbing.Pitch = speed / 5.5
else
sClimbing:Stop()
end
prevState = "Climb"
end
-- connect up
function stopLoopedSounds()
sRunning:Stop()
sClimbing:Stop()
sSwimming:Stop()
end
function onState(state, sound)
if state then
sound:Play()
end
end
if hasPlayer == nil then
Humanoid.Died:connect(onDied)
Humanoid.Running:connect(onRunning)
Humanoid.Swimming:connect(onSwimming)
Humanoid.Climbing:connect(onClimbing)
Humanoid.Jumping:connect(function(state)
if useClassicSounds then
onState(state, classic_sJumping)
else
onStateNoStop(state, sJumping)
prevState = "Jump"
end
end)
Humanoid.GettingUp:connect(function(state)
if useClassicSounds then
onState(state, classic_sGettingUp)
else
stopLoopedSounds()
onStateNoStop(state, sGettingUp)
prevState = "GetUp"
end
end)
Humanoid.FreeFalling:connect(function(state)
if useClassicSounds then
onState(state, classic_sFreeFalling)
if classic_sJumping.IsPlaying then
classic_sJumping:Stop()
end
else
stopLoopedSounds()
onStateFall(state, sFreeFalling)
prevState = "FreeFall"
end
end)
Humanoid.FallingDown:connect(function(state)
if useClassicSounds then
onState(state, classic_sFallingDown)
else
stopLoopedSounds()
end
end)
Humanoid.StateChanged:connect(function(old, new)
if not (new.Name == "Dead" or
new.Name == "Running" or
new.Name == "RunningNoPhysics" or
new.Name == "Swimming" or
new.Name == "Jumping" or
new.Name == "GettingUp" or
new.Name == "Freefall" or
new.Name == "FallingDown") and not useClassicSounds then
stopLoopedSounds()
end
end)
GameSettings.Changed:connect(function(property)
if property == "VirtualVersion" then
useClassicSounds = GameSettings.VirtualVersion == Enum.VirtualVersion['2012'] or GameSettings.VirtualVersion == Enum.VirtualVersion['2013']
if useClassicSounds then
stopLoopedSounds()
end
end
end)
end
]]> </ProtectedString>
</Properties>
<Item class="LocalScript" referent="RBXACC3E7AAF68642CC9341039CBCE06F78">
<Properties>
<bool name="Disabled">false</bool>
<Content name="LinkedSource">
<null></null>
</Content>
<string name="Name">LocalSound</string>
<ProtectedString name="Source"><![CDATA[--This local script will run only for the player whos character it is in. It's changes to the sounds will replicate as they are changes to the character.
-- util
function waitForChild(parent, childName)
local child = parent:findFirstChild(childName)
if child then return child end
while true do
child = parent.ChildAdded:wait()
if child.Name==childName then return child end
end
end
-- declarations
local Figure = script.Parent.Parent
local Head = waitForChild(Figure, "Head")
local Humanoid = waitForChild(Figure, "Humanoid")
local sGettingUp = waitForChild(Head, "GettingUp")
local sDied = waitForChild(Head, "Died")
local sFreeFalling = waitForChild(Head, "FreeFalling")
local sJumping = waitForChild(Head, "Jumping")
local sLanding = waitForChild(Head, "Landing")
local sSplash = waitForChild(Head, "Splash")
local sRunning = waitForChild(Head, "Running")
sRunning.Looped = true
local sSwimming = waitForChild(Head, "Swimming")
sSwimming.Looped = true
local sClimbing =waitForChild(Head, "Climbing")
sClimbing.Looped = true
local classic_sFallingDown = waitForChild(Head, "classic_FallingDown")
local classic_sFreeFalling = waitForChild(Head, "classic_FreeFalling")
local classic_sGettingUp = waitForChild(Head, "classic_GettingUp")
local classic_sJumping = waitForChild(Head, "classic_Jumping")
local classic_sRunning = waitForChild(Head, "classic_Running")
classic_sRunning.Looped = true
local GameSettings = UserSettings().GameSettings
local useClassicSounds = GameSettings.VirtualVersion == Enum.VirtualVersion['2012'] or GameSettings.VirtualVersion == Enum.VirtualVersion['2013']
local prevState = "None"
-- functions
function onDied()
stopLoopedSounds()
sDied:Play()
end
local fallCount = 0
local fallSpeed = 0
function onStateFall(state, sound)
fallCount = fallCount + 1
if state then
sound.Volume = 0
sound:Play()
Spawn( function()
local t = 0
local thisFall = fallCount
while t < 1.5 and fallCount == thisFall do
local vol = math.max(t - 0.3 , 0)
sound.Volume = vol
wait(0.1)
t = t + 0.1
end
end)
else
sound:Stop()
end
fallSpeed = math.max(fallSpeed, math.abs(Head.Velocity.Y))
end
function onStateNoStop(state, sound)
if state then
sound:Play()
end
end
function onRunning(speed)
if useClassicSounds then
if speed > 0.01 then
classic_sRunning:Play()
else
classic_sRunning:Pause()
end
return
end
sClimbing:Stop()
sSwimming:Stop()
if (prevState == "FreeFall" and fallSpeed > 0.1) then
local vol = math.min(1.0, math.max(0.0, (fallSpeed - 50) / 110))
sLanding.Volume = vol
sLanding:Play()
fallSpeed = 0
end
if speed>0.5 then
sRunning:Play()
sRunning.Pitch = speed / 8.0
else
sRunning:Stop()
end
prevState = "Run"
end
function onSwimming(speed)
if (prevState ~= "Swim" and speed > 0.1) then
local volume = math.min(1.0, speed / 350)
sSplash.Volume = volume
sSplash:Play()
prevState = "Swim"
end
sClimbing:Stop()
sRunning:Stop()
sSwimming.Pitch = 1.6
sSwimming:Play()
end
function onClimbing(speed)
sRunning:Stop()
sSwimming:Stop()
if speed>0.01 then
sClimbing:Play()
sClimbing.Pitch = speed / 5.5
else
sClimbing:Stop()
end
prevState = "Climb"
end
-- connect up
function stopLoopedSounds()
sRunning:Stop()
sClimbing:Stop()
sSwimming:Stop()
end
function onState(state, sound)
if state then
sound:Play()
end
end
Humanoid.Died:connect(onDied)
Humanoid.Running:connect(onRunning)
Humanoid.Swimming:connect(onSwimming)
Humanoid.Climbing:connect(onClimbing)
Humanoid.Jumping:connect(function(state)
if useClassicSounds then
onState(state, classic_sJumping)
else
onStateNoStop(state, sJumping)
prevState = "Jump"
end
end)
Humanoid.GettingUp:connect(function(state)
if useClassicSounds then
onState(state, classic_sGettingUp)
else
stopLoopedSounds()
onStateNoStop(state, sGettingUp)
prevState = "GetUp"
end
end)
Humanoid.FreeFalling:connect(function(state)
if useClassicSounds then
if classic_sJumping.IsPlaying then
classic_sJumping:Stop()
end
onState(state, classic_sFreeFalling)
else
stopLoopedSounds()
onStateFall(state, sFreeFalling)
prevState = "FreeFall"
end
end)
Humanoid.FallingDown:connect(function(state)
if useClassicSounds then
onState(state, classic_sFallingDown)
else
stopLoopedSounds()
end
end)
Humanoid.StateChanged:connect(function(old, new)
if not (new.Name == "Dead" or
new.Name == "Running" or
new.Name == "RunningNoPhysics" or
new.Name == "Swimming" or
new.Name == "Jumping" or
new.Name == "GettingUp" or
new.Name == "Freefall" or
new.Name == "FallingDown") and not useClassicSounds then
stopLoopedSounds()
end
end)
GameSettings.Changed:connect(function(property)
if property == "VirtualVersion" then
useClassicSounds = GameSettings.VirtualVersion == Enum.VirtualVersion['2012'] or GameSettings.VirtualVersion == Enum.VirtualVersion['2013']
if useClassicSounds then
stopLoopedSounds()
end
end
end)
]]> </ProtectedString>
</Properties>
</Item>
</Item>
</roblox>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More