mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-05 05:07:48 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Roblox.cpp
|
||||
* MacClient
|
||||
*
|
||||
* Created by Tony on 1/26/11.
|
||||
* Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "RobloxPlayerAppDelegate.h"
|
||||
#import "CMCrashReporter.h"
|
||||
|
||||
#include "Roblox.h"
|
||||
#include "FunctionMarshaller.h"
|
||||
#include "rbx/CEvent.h"
|
||||
#include "rbx/log.h"
|
||||
#include "util/guid.h"
|
||||
#include "Util/FileSystem.h"
|
||||
#include "RobloxView.h"
|
||||
#include "v8datamodel/TeleportCallback.h"
|
||||
#include "FastLog.h"
|
||||
#include <semaphore.h>
|
||||
|
||||
const std::string& GetBaseURL();
|
||||
|
||||
void callTerminateApp()
|
||||
{
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
|
||||
void *Roblox::theInstance = NULL;
|
||||
boost::scoped_ptr<boost::thread> Roblox::singleRunningInstance;
|
||||
sem_t *Roblox::uniqSemaphore = NULL;
|
||||
bool Roblox::needTerminateCall = true;
|
||||
|
||||
shared_ptr<RBX::TeleportCallback> Roblox::callback;
|
||||
|
||||
// This function will locate the path to our application on OS X,
|
||||
// unlike windows you cannot rely on the current working directory
|
||||
// for locating your configuration files and resources.
|
||||
std::string macBundlePath()
|
||||
{
|
||||
char path[1024];
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
assert(mainBundle);
|
||||
|
||||
CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
|
||||
assert(mainBundleURL);
|
||||
|
||||
CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);
|
||||
assert(cfStringRef);
|
||||
|
||||
CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);
|
||||
|
||||
CFRelease(mainBundleURL);
|
||||
CFRelease(cfStringRef);
|
||||
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
class LogProvider : public RBX::ILogProvider
|
||||
{
|
||||
boost::thread_specific_ptr<RBX::Log> log;
|
||||
boost::filesystem::path logDir;
|
||||
boost::mutex breakPadLogMutex;
|
||||
int breakpadCount;
|
||||
std::vector<RBX::Log*> fastLogChannels;
|
||||
std::string logGuid;
|
||||
static RBX::mutex fastLogChannelsLock;
|
||||
|
||||
static LogProvider* mainLogManager;
|
||||
public:
|
||||
LogProvider()
|
||||
:breakpadCount(0)
|
||||
{
|
||||
RBX::Guid::generateRBXGUID(logGuid);
|
||||
logGuid = logGuid.substr(3, 6);
|
||||
logDir = RBX::FileSystem::getLogsDirectory();
|
||||
|
||||
std::cout << "Writing logs to " << logDir.string() << " with GUID " + logGuid << '\n';
|
||||
|
||||
mainLogManager = this;
|
||||
|
||||
FLog::SetExternalLogFunc(LogProvider::FastLogMessage);
|
||||
}
|
||||
|
||||
~LogProvider()
|
||||
{
|
||||
// Do not delete Log files on Mac Player exit
|
||||
// Look for Log under /tmp/roblox.xyz/Roblox/Logs
|
||||
// tmp folder is auto cleaned on restart of Mac
|
||||
//RBX::FileSystem::clearCacheDirectory("Logs");
|
||||
}
|
||||
|
||||
virtual RBX::Log* provideLog()
|
||||
{
|
||||
RBX::Log* result = log.get();
|
||||
if (!result)
|
||||
{
|
||||
std::string name = RBX::get_thread_name();
|
||||
boost::filesystem::path logFile = logDir / ("log_" + logGuid + ".txt");
|
||||
|
||||
result = new RBX::Log(logFile.c_str(), name.c_str());
|
||||
log.reset(result);
|
||||
|
||||
boost::mutex::scoped_lock lock(breakPadLogMutex);
|
||||
if (breakpadCount++ < 10)
|
||||
{
|
||||
Roblox::addLogToBreakpad(logFile.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void FastLogMessage(FLog::Channel id, const char* message) {
|
||||
|
||||
RBX::mutex::scoped_lock lock(fastLogChannelsLock);
|
||||
|
||||
if(mainLogManager)
|
||||
{
|
||||
if(id >= mainLogManager->fastLogChannels.size())
|
||||
mainLogManager->fastLogChannels.resize(id+1, NULL);
|
||||
|
||||
if(mainLogManager->fastLogChannels[id] == NULL)
|
||||
{
|
||||
char temp[20];
|
||||
snprintf(temp, 19, "log_%s_%u.txt", mainLogManager->logGuid.c_str(), id);
|
||||
temp[19] = 0;
|
||||
boost::filesystem::path logFile = mainLogManager->logDir / temp;
|
||||
|
||||
mainLogManager->fastLogChannels[id] = new RBX::Log(logFile.c_str(), "Log Channel");
|
||||
Roblox::addLogToBreakpad(logFile.c_str());
|
||||
}
|
||||
|
||||
mainLogManager->fastLogChannels[id]->writeEntry(RBX::Log::Information, message);
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteFastLogDump(){
|
||||
RBX::mutex::scoped_lock lock(fastLogChannelsLock);
|
||||
|
||||
if(mainLogManager)
|
||||
{
|
||||
boost::filesystem::path logFile = mainLogManager->logDir / ("log_" + mainLogManager->logGuid + "_dump.txt");
|
||||
|
||||
FLog::WriteFastLogDump(logFile.c_str(), 2048);
|
||||
Roblox::addLogToBreakpad(logFile.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void MacWriteFastLogDump()
|
||||
{
|
||||
LogProvider::WriteFastLogDump();
|
||||
}
|
||||
|
||||
LogProvider* LogProvider::mainLogManager = NULL;
|
||||
RBX::mutex LogProvider::fastLogChannelsLock;
|
||||
|
||||
static LogProvider logProvider;
|
||||
|
||||
class Teleporter : public RBX::TeleportCallback
|
||||
{
|
||||
void *_instance;
|
||||
public:
|
||||
Teleporter(void *instance) { _instance = instance; }
|
||||
|
||||
virtual void doTeleport(const std::string &url, const std::string &ticket, const std::string &script)
|
||||
{
|
||||
RobloxView *view = nil;
|
||||
|
||||
RobloxPlayerAppDelegate *appDelegate = (RobloxPlayerAppDelegate*)_instance;
|
||||
view = [appDelegate robloxView];
|
||||
|
||||
view->stopJobs();
|
||||
view->marshalTeleport(url, ticket, script);
|
||||
}
|
||||
|
||||
virtual bool isTeleportEnabled() const { return true; }
|
||||
};
|
||||
|
||||
void Roblox::addLogToBreakpad(const char* log)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSResponder *responder = (NSResponder *) theInstance;
|
||||
NSString* s = [NSString stringWithFormat:@"%s", log];
|
||||
[responder performSelectorOnMainThread:@selector(addLogFile:)
|
||||
withObject:s waitUntilDone:NO];
|
||||
[pool release];
|
||||
}
|
||||
|
||||
void Roblox::addBreakPadKeyValue(const char* key, int value)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSResponder *responder = (NSResponder *) theInstance;
|
||||
NSString* s = [NSString stringWithFormat:@"%s", key];
|
||||
NSString* v = [NSString stringWithFormat:@"%d", value];
|
||||
|
||||
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:s, @"key", v, @"value", nil];
|
||||
[responder performSelectorOnMainThread:@selector(addBreakPadKeyValueFromDictionary:)
|
||||
withObject:info waitUntilDone:NO];
|
||||
[pool release];
|
||||
|
||||
}
|
||||
|
||||
static char uniqPlayerId[] = "/RobloxPlayerUniq";
|
||||
|
||||
bool Roblox::isOtherRunning()
|
||||
{
|
||||
pid_t id = getpid();
|
||||
///NSLog(@"isOtherRunning - pid = %i trying to open semaphore", id);
|
||||
sem_t *sem = sem_open(uniqPlayerId, O_CREAT | O_EXCL, 0666, 0);
|
||||
if (sem != SEM_FAILED)
|
||||
{
|
||||
NSLog(@"isOtherRunning - pid = %i waiting on semaphore", id);
|
||||
uniqSemaphore = sem; // I guess we need atomic echange????
|
||||
sem_wait(sem);
|
||||
uniqSemaphore = NULL;
|
||||
|
||||
NSLog(@"isOtherRunning - pid = %i closing semaphore", id);
|
||||
sem_close(sem);
|
||||
sem_unlink(uniqPlayerId);
|
||||
return false;
|
||||
}
|
||||
//NSLog(@"isOtherRunning - pid = %i semaphore open failed", id);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Roblox::terminateOther()
|
||||
{
|
||||
sem_t *sem = sem_open(uniqPlayerId, 0);
|
||||
if (sem != SEM_FAILED)
|
||||
{
|
||||
//NSLog(@"terminateOther - pid = %i semaphore is opened", id);
|
||||
sem_post(sem);
|
||||
sem_close(sem);
|
||||
}
|
||||
}
|
||||
|
||||
void Roblox::terminateWaiter()
|
||||
{
|
||||
pid_t id = getpid();
|
||||
NSLog(@"Roblox::terminateWaiter - pid = %i", id);
|
||||
while(isOtherRunning())
|
||||
{
|
||||
terminateOther();
|
||||
usleep(1000*100); //sleep 100 msecs
|
||||
}
|
||||
|
||||
if (needTerminateCall)
|
||||
{
|
||||
NSLog(@"Roblox::terminateWaiter - pid = %i, terminating app", id);
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
}
|
||||
|
||||
bool Roblox::initInstance(void *instance, bool isApp)
|
||||
{
|
||||
singleRunningInstance.reset(new boost::thread(&Roblox::terminateWaiter));
|
||||
|
||||
theInstance = instance;
|
||||
|
||||
callback = shared_ptr<RBX::TeleportCallback>(new Teleporter(instance));
|
||||
RBX::TeleportService::SetCallback(callback.get());
|
||||
RBX::TeleportService::SetBaseUrl(::GetBaseURL().c_str());
|
||||
|
||||
RBX::Log::setLogProvider(&logProvider);
|
||||
|
||||
if(globalInit(isApp))
|
||||
{
|
||||
[CMCrashReporter check];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Roblox::releaseTerminateWaiter()
|
||||
{
|
||||
if (uniqSemaphore != NULL)
|
||||
{
|
||||
pid_t id = getpid();
|
||||
NSLog(@"Roblox::shutdownInstance - pid = %i, thread is still waiting, signaling semaphore", id);
|
||||
|
||||
needTerminateCall = false;
|
||||
sem_post(uniqSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
void Roblox::shutdownInstance()
|
||||
{
|
||||
releaseTerminateWaiter();
|
||||
|
||||
globalShutdown();
|
||||
|
||||
theInstance = NULL;
|
||||
}
|
||||
|
||||
// FunctionMarshaller help - posts worker thread message to UI thread and deals with it next time through
|
||||
void Roblox::sendAppEvent(void *pClosure)
|
||||
{
|
||||
NSGraphicsContext *context = nil;
|
||||
NSInteger windowNumber = 0;
|
||||
NSPoint location;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSEvent *ev = [[NSEvent otherEventWithType:NSApplicationDefined location:location modifierFlags:0 timestamp:0 windowNumber:windowNumber context:context
|
||||
subtype:0 data1:(NSInteger)pClosure data2:0] retain];
|
||||
|
||||
|
||||
RBX::CEvent *waitEvent = ((RBX::FunctionMarshaller::Closure *) pClosure)->waitEvent;
|
||||
BOOL waitFlag = (waitEvent == NULL);
|
||||
|
||||
// TBD: Make sure the marshallFunction: selector actually exists!
|
||||
NSResponder *responder = (NSResponder *) theInstance;
|
||||
[responder performSelectorOnMainThread:@selector(marshallFunction:) withObject:ev waitUntilDone:waitFlag];
|
||||
|
||||
if (waitEvent)
|
||||
{
|
||||
waitEvent->Wait();
|
||||
}
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
void Roblox::postAppEvent(void *pClosure)
|
||||
{
|
||||
NSGraphicsContext *context = nil;
|
||||
NSInteger windowNumber = 0;
|
||||
NSPoint location;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSEvent *ev = [[NSEvent otherEventWithType:NSApplicationDefined location:location modifierFlags:0 timestamp:0 windowNumber:windowNumber context:context
|
||||
subtype:0 data1:(NSInteger)pClosure data2:0] retain];
|
||||
|
||||
|
||||
// TBD: Make sure the marshallFunction: selector actually exists!
|
||||
NSResponder *responder = (NSResponder *) theInstance;
|
||||
[responder performSelectorOnMainThread:@selector(marshallFunction:) withObject:ev waitUntilDone:NO];
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
void Roblox::processAppEvents()
|
||||
{
|
||||
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource)
|
||||
;
|
||||
}
|
||||
|
||||
void Roblox::handleLeaveGame(void *appWindow)
|
||||
{
|
||||
RobloxPlayerAppDelegate *delegate = (RobloxPlayerAppDelegate *) appWindow;
|
||||
[delegate handleLeaveGame];
|
||||
}
|
||||
|
||||
void Roblox::handleShutdownClient(void *appWindow)
|
||||
{
|
||||
RobloxPlayerAppDelegate *delegate = (RobloxPlayerAppDelegate *) appWindow;
|
||||
[delegate handleShutdownClient];
|
||||
}
|
||||
|
||||
void Roblox::handleToggleFullScreen(void *appWindow)
|
||||
{
|
||||
RobloxPlayerAppDelegate *delegate = (RobloxPlayerAppDelegate *) appWindow;
|
||||
[delegate handleToggleFullScreen];
|
||||
}
|
||||
|
||||
bool Roblox::inFullScreenMode(void *appWindow)
|
||||
{
|
||||
RobloxPlayerAppDelegate *delegate = (RobloxPlayerAppDelegate *) appWindow;
|
||||
|
||||
bool fullscreen = [delegate inFullScreenMode];
|
||||
return fullscreen;
|
||||
}
|
||||
Reference in New Issue
Block a user