This commit is contained in:
watrabi
2025-09-18 17:55:52 -04:00
commit 977f1ff4b8
15030 changed files with 17324420 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
#include "ControllerBuffer.h"
#include "v8datamodel/DataModel.h"
#include "v8datamodel/GamepadService.h"
#include "XboxGameController.h"
using namespace Windows::Foundation::Collections;
using namespace RBX;
#define INPUT_POLLING_HZ 90.0f
ControllerBuffer::ControllerBuffer() :
xboxGameController(NULL)
{}
void ControllerBuffer::updateBuffer()
{
if (xboxGameController == nullptr)
{
return;
}
boost::mutex::scoped_lock lock(changeInputBufferMutex);
IVectorView<IGamepad^>^ gamepads = Windows::Xbox::Input::Gamepad::Gamepads;
for ( unsigned int i = 0; i < gamepads->Size; ++i )
{
int rbxGamepadInt = xboxGameController->getRbxGamepadIntFromGamepad(gamepads->GetAt(i));
if (rbxGamepadInt >= 0)
{
IGamepadReading^ reading = gamepads->GetAt(i)->GetCurrentReading();
bufferGamepadButtons(rbxGamepadInt, reading);
bufferGamepadAxis(rbxGamepadInt, reading);
}
}
}
void ControllerBuffer::processButton(InputObject::UserInputType userInputType, const RBX::KeyCode buttonCode, const int buttonState)
{
if (buttonCode == SDLK_UNKNOWN || userInputType == InputObject::TYPE_NONE)
{
return;
}
InputObject::UserInputState newState = (buttonState == 1) ? InputObject::INPUT_STATE_BEGIN : InputObject::INPUT_STATE_END;
GamepadValue gamepadButtonCombo(userInputType, buttonCode);
GamepadValueState newGamepadButtonState(Vector3(0,0,buttonState), newState);
if (bufferedInput.find(gamepadButtonCombo) == bufferedInput.end() ||
bufferedInput[gamepadButtonCombo].back().first != newGamepadButtonState.first)
{
bufferedInput[gamepadButtonCombo].push_back(newGamepadButtonState);
}
}
void ControllerBuffer::bufferGamepadButtons(const int controllerIndex, IGamepadReading^& gamepadReading)
{
InputObject::UserInputType gamepadType = GamepadService::getGamepadEnumForInt(controllerIndex);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONA, gamepadReading->IsAPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONB, gamepadReading->IsBPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONX, gamepadReading->IsXPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONY, gamepadReading->IsYPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_DPADLEFT, gamepadReading->IsDPadLeftPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_DPADRIGHT, gamepadReading->IsDPadRightPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_DPADUP, gamepadReading->IsDPadUpPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_DPADDOWN, gamepadReading->IsDPadDownPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONL1, gamepadReading->IsLeftShoulderPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONR1, gamepadReading->IsRightShoulderPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONL3, gamepadReading->IsLeftThumbstickPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONR3, gamepadReading->IsRightThumbstickPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONSTART, gamepadReading->IsMenuPressed ? 1 : 0);
processButton(gamepadType, SDLK_GAMEPAD_BUTTONSELECT, gamepadReading->IsViewPressed ? 1 : 0);
}
void ControllerBuffer::processAxis(RBX::InputObject::UserInputType userInputType, const RBX::KeyCode axisCode, const Vector3 axisValue)
{
if (axisCode == SDLK_UNKNOWN || userInputType == InputObject::TYPE_NONE)
{
return;
}
RBX::InputObject::UserInputState newState = RBX::InputObject::INPUT_STATE_CHANGE;
if (axisValue == G3D::Vector3::zero())
{
newState = RBX::InputObject::INPUT_STATE_END;
}
else if (axisValue.z >= 1.0f)
{
newState = RBX::InputObject::INPUT_STATE_BEGIN;
}
GamepadValue gamepadAxisCombo(userInputType, axisCode);
GamepadValueState newGamepadAxisState(axisValue, newState);
if (bufferedInput.find(gamepadAxisCombo) == bufferedInput.end() ||
bufferedInput[gamepadAxisCombo].back().first != newGamepadAxisState.first)
{
bufferedInput[gamepadAxisCombo].push_back(newGamepadAxisState);
}
}
void ControllerBuffer::bufferGamepadAxis(const int controllerIndex, IGamepadReading^& gamepadReading)
{
InputObject::UserInputType gamepadType = GamepadService::getGamepadEnumForInt(controllerIndex);
processAxis(gamepadType, SDLK_GAMEPAD_THUMBSTICK1, Vector3(gamepadReading->LeftThumbstickX, gamepadReading->LeftThumbstickY, 0));
processAxis(gamepadType, SDLK_GAMEPAD_THUMBSTICK2, Vector3(gamepadReading->RightThumbstickX, gamepadReading->RightThumbstickY, 0));
processAxis(gamepadType, SDLK_GAMEPAD_BUTTONL2, Vector3(0, 0, gamepadReading->LeftTrigger));
processAxis(gamepadType, SDLK_GAMEPAD_BUTTONR2, Vector3(0, 0, gamepadReading->RightTrigger));
}
ControllerBuffer::GamepadValueBufferMap ControllerBuffer::getBufferedInput()
{
GamepadValueBufferMap tmpMap;
{
boost::mutex::scoped_lock lock(changeInputBufferMutex);
bufferedInput.swap(tmpMap);
}
return tmpMap;
}
float ControllerBuffer::getPollingMsec()
{
return (1.0f/INPUT_POLLING_HZ) * 1000.0f;
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "rbx/rbxTime.h"
#include <boost/unordered_map.hpp>
#include "v8datamodel/InputObject.h"
using namespace Windows::Xbox::Input;
class XboxGameController;
class ControllerBuffer
{
public:
typedef std::pair<RBX::InputObject::UserInputType, RBX::KeyCode> GamepadValue;
typedef std::pair<RBX::Vector3, RBX::InputObject::UserInputState> GamepadValueState;
typedef std::vector<GamepadValueState> GamepadValueStateHistoryVector;
typedef boost::unordered_map<GamepadValue, GamepadValueStateHistoryVector> GamepadValueBufferMap;
private:
GamepadValueBufferMap bufferedInput;
boost::mutex changeInputBufferMutex;
XboxGameController* xboxGameController;
void bufferGamepadButtons(const int controllerIndex, IGamepadReading^& gamepadReading);
void bufferGamepadAxis(const int controllerIndex, IGamepadReading^& gamepadReading);
void processButton(RBX::InputObject::UserInputType userInputType, const RBX::KeyCode buttonCode, const int buttonState);
void processAxis(RBX::InputObject::UserInputType userInputType, const RBX::KeyCode axisCode, const RBX::Vector3 axisValue);
public:
ControllerBuffer();
void setXboxGameController(XboxGameController* newController) {xboxGameController = newController;}
void updateBuffer();
float getPollingMsec();
GamepadValueBufferMap getBufferedInput();
};
@@ -0,0 +1 @@
?
+152
View File
@@ -0,0 +1,152 @@
#include "KeyboardProvider.h"
#include "XboxService.h"
#include "XboxUtils.h"
#include "async.h"
#include <thread>
#include "v8datamodel/TextBox.h"
using namespace Windows::Xbox::UI;
using namespace RBX;
volatile long KeyboardProvider::keyboardOn = 0;
void KeyboardProvider::registerTextBoxListener(RBX::DataModel* dm)
{
if (auto uis = RBX::ServiceProvider::create<UserInputService>(dm))
{
showKeyboardSignal = uis->textBoxGainFocus.connect(boost::bind(&KeyboardProvider::showKeyBoard, this, _1));
}
}
void KeyboardProvider::showKeyBoard(std::string& title, std::string& description, const std::string& defaultText, RBX::XboxKeyBoardType keyboardType, std::function<void(Platform::String^)>& successLambda, std::function<void(void)>& cancelLambda)
{
if( InterlockedCompareExchange(&keyboardOn, 1, 0 ) )
return;
VirtualKeyboardInputScope inputScope = VirtualKeyboardInputScope::Default;
switch (keyboardType)
{
case RBX::xbKeyBoard_Default:
inputScope = VirtualKeyboardInputScope::Default;
break;
case RBX::xbKeyBoard_EmailSmtpAddress:
inputScope = VirtualKeyboardInputScope::EmailSmtpAddress;
break;
case RBX::xbKeyBoard_Number:
inputScope = VirtualKeyboardInputScope::Number;
break;
case RBX::xbKeyBoard_Password:
inputScope = VirtualKeyboardInputScope::Password;
break;
case RBX::xbKeyBoard_Search:
inputScope = VirtualKeyboardInputScope::Search;
break;
case RBX::xbKeyBoard_TelephoneNumber:
inputScope = VirtualKeyboardInputScope::TelephoneNumber;
break;
case RBX::xbKeyBoard_Url:
inputScope = VirtualKeyboardInputScope::Url;
break;
default:
RBXASSERT(false); // new type?
break;
}
try
{
async(SystemUI::ShowVirtualKeyboardAsync(ref new Platform::String(s2ws(&defaultText).data()), ref new Platform::String(s2ws(&title).data()), ref new Platform::String(s2ws(&description).data()), inputScope))
.complete(successLambda)
.cancelled(cancelLambda)
.error(cancelLambda)
.detach();
}
catch(Platform::Exception^ e)
{
dprintf("ShowVirtualKeyboard exception: [%u] %S\n", (unsigned)e->HResult, e->Message->Data() );
cancelLambda();
}
}
void KeyboardProvider::showKeyBoardLua(std::string& title, std::string& description, std::string& defaultText, RBX::XboxKeyBoardType keyboardType, RBX::DataModel* dm)
{
std::function<void(void)> cancelLambda = [=]() -> void
{
dm->submitTask([=](...)
{
if(PlatformService* p = ServiceProvider::find<PlatformService>(dm))
p->keyboardClosedSignal(defaultText.data());
}
, DataModelJob::Write);
InterlockedExchange(&keyboardOn, 0);
};
std::function<void(Platform::String^ defaultText)> successLambda = [=](Platform::String^ defaultText) -> void
{
dm->submitTask([=](...)
{
std::string textBoxValue = ws2s(defaultText->Data());
if(PlatformService* p = ServiceProvider::find<PlatformService>(dm))
p->keyboardClosedSignal(textBoxValue.data());
}
, DataModelJob::Write);
InterlockedExchange(&keyboardOn, 0);
};
showKeyBoard(title, description, defaultText, keyboardType, successLambda, cancelLambda);
}
void KeyboardProvider::showKeyBoard(shared_ptr<RBX::Instance> instance)
{
shared_ptr<RBX::TextBox> textBox = RBX::Instance::fastSharedDynamicCast<RBX::TextBox>(instance);
RBX::DataModel* dm = DataModel::get(instance.get());
if (dm && textBox)
{
std::string text = textBox->getText();
std::wstring wstr(text.begin(), text.end());
Platform::String^ defaultText = ref new Platform::String(wstr.c_str());
std::function<void(void)> cancelLambda = [=]() -> void
{
if (textBox)
{
dm->submitTask([=](...)
{
if (auto uis = RBX::ServiceProvider::create<UserInputService>(dm))
uis->textboxDidFinishEditing(text.c_str(), false);
}
, DataModelJob::Write);
}
InterlockedExchange(&keyboardOn, 0);
};
std::function<void(Platform::String^ defaultText)> successLambda = [=](Platform::String^ defaultText) -> void
{
if (textBox)
{
std::string textBoxValue = ws2s(defaultText->Data());
dm->submitTask([=](...)
{
if (auto uis = RBX::ServiceProvider::create<UserInputService>(dm))
uis->textboxDidFinishEditing(textBoxValue.c_str(), true);
}
, DataModelJob::Write);
}
InterlockedExchange(&keyboardOn, 0);
};
std::string title = "Text Entry";
std::string desc = "Please input text";
showKeyBoard(title, desc, textBox->getText(), RBX::xbKeyBoard_Default, successLambda, cancelLambda);
}
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include "V8Tree/Instance.h"
#include <atomic>
namespace RBX
{
class DataModel;
enum XboxKeyBoardType;
}
class KeyboardProvider
{
public:
void registerTextBoxListener(RBX::DataModel* dm);
void showKeyBoard(shared_ptr<RBX::Instance> instance);
void showKeyBoardLua(std::string& title, std::string& description, std::string& defaultText, RBX::XboxKeyBoardType keyboardType, RBX::DataModel* dm);
private:
void showKeyBoard(std::string& title, std::string& description, const std::string& defaultText, RBX::XboxKeyBoardType keyboardType, std::function<void(Platform::String^)>& successLambda, std::function<void(void)>& cancelLambda);
rbx::signals::scoped_connection showKeyboardSignal;
static volatile long keyboardOn;
};
+83
View File
@@ -0,0 +1,83 @@
{
"EndPoints": [
{
"Protocol": "https",
"Host": "api.sitetest3.pizzaboxer.fun",
"RelyingParty": "https://api.sitetest3.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.sitetest2.pizzaboxer.fun",
"RelyingParty": "https://api.sitetest2.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.sitetest1.pizzaboxer.fun",
"RelyingParty": "https://api.sitetest1.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.gametest5.pizzaboxer.fun",
"RelyingParty": "https://api.gametest5.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.gametest4.pizzaboxer.fun",
"RelyingParty": "https://api.gametest4.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.gametest3.pizzaboxer.fun",
"RelyingParty": "https://api.gametest3.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.gametest2.pizzaboxer.fun",
"RelyingParty": "https://api.gametest2.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.gametest1.pizzaboxer.fun",
"RelyingParty": "https://api.gametest1.pizzaboxer.fun/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "api.watrbx.wtf",
"RelyingParty": "https://api.watrbx.wtf/",
"TokenType": "JWT",
"HostType": "fqdn"
},
{
"Protocol": "https",
"Host": "*",
"RelyingParty": "http://xboxlive.com",
"TokenType": "JWT",
"HostType": "ip"
},
{
"Protocol": "https",
"Host": "*",
"HostType": "wildcard"
},
{
"Protocol": "http",
"Host": "*",
"HostType": "wildcard"
}]
}
+103
View File
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:mx="http://schemas.microsoft.com/appx/2013/xbox/manifest" IgnorableNamespaces="mx">
<!--- 'Name' and 'Version' appear in the package path created by deploy -->
<Identity Name="roblox"
Publisher="CN=ROBLOX, O=ROBLOX, L=San Mateo, S=California, C=US"
Version="1.0.0.0" />
<Properties>
<DisplayName>ROBLOX</DisplayName>
<PublisherDisplayName>ROBLOX</PublisherDisplayName>
<Logo>img/roblox.png</Logo>
<Description>Community Created Gaming. Limitless Possibilities.</Description>
</Properties>
<Prerequisites>
<OSMinVersion>6.2</OSMinVersion>
<OSMaxVersionTested>6.2</OSMaxVersionTested>
</Prerequisites>
<Resources>
<Resource Language="en-us"/>
</Resources>
<Applications>
<!--- Debug config -->
<!--- 'Id' is in the aumid returned from deploy -->
<!--- 'Executable' must match the .exe produced by the build -->
<Application Id="RobloxClient0"
Executable="XboxClient.exe"
EntryPoint="XboxClient.App">
<!--- all fields except DisplayName not yet implemented -->
<VisualElements
DisplayName="ROBLOX"
Logo="img/logo208.png"
SmallLogo="img/logo100.png"
Description="Description"
ForegroundText="dark"
BackgroundColor="#000040">
<DefaultTile WideLogo="img/robloxWide.png" ShortName ="ROBLOX" />
<SplashScreen Image="img/roblox.png" />
</VisualElements>
<mx:Ratings Category="game">
<mx:Rating>ESRB:E10</mx:Rating>
</mx:Ratings>
<Extensions>
<mx:Extension Category="xbox.live">
<mx:XboxLive
TitleId="1465F7BC"
PrimaryServiceConfigId="bab50100-e49a-4ce8-b16f-918d1465f7bc"
RequireXboxLive="true" />
</mx:Extension>
<mx:Extension Category="windows.xbox.networking">
<!-- NOTE: talk to Michal before you mess with this section. I'm dead serious. -->
<mx:XboxNetworkingManifest>
<mx:SocketDescriptions>
<mx:SocketDescription Name="MultiplayerSocketUdp" SecureIpProtocol="Udp" BoundPort="8700"> <!-- particularly this part! -->
<mx:AllowedUsages>
<mx:SecureDeviceSocketUsage Type="Initiate" />
<mx:SecureDeviceSocketUsage Type="Accept" />
<mx:SecureDeviceSocketUsage Type="SendGameData" />
<mx:SecureDeviceSocketUsage Type="ReceiveGameData" />
<mx:SecureDeviceSocketUsage Type="SendChat" />
<mx:SecureDeviceSocketUsage Type="ReceiveChat" />
</mx:AllowedUsages>
</mx:SocketDescription>
</mx:SocketDescriptions>
<mx:SecureDeviceAssociationTemplates>
<mx:SecureDeviceAssociationTemplate Name="MultiplayerUdp" InitiatorSocketDescription="MultiplayerSocketUdp" AcceptorSocketDescription="MultiplayerSocketUdp" MultiplayerSessionRequirement="Required">
<mx:AllowedUsages>
<mx:SecureDeviceAssociationUsage Type="Default" />
</mx:AllowedUsages>
</mx:SecureDeviceAssociationTemplate>
</mx:SecureDeviceAssociationTemplates>
</mx:XboxNetworkingManifest>
</mx:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClientServer" />
<mx:Capability Name="kinectAudio"/>
<mx:Capability Name="kinectGamechat"/>
</Capabilities>
<Extensions>
<mx:PackageExtension Category="xbox.storage">
<mx:Storage>
<mx:PersistentLocalStorage SizeInMegabytes="4095"/>
</mx:Storage>
</mx:PackageExtension>
</Extensions>
</Package>
+39
View File
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<Chunk Id="999">
<FileGroup DestinationPath="\" SourcePath="." Include="*.xml"/>
<FileGroup DestinationPath="\img" SourcePath="img" Include="*.*"/>
</Chunk>
<Chunk Id="1000">
<FileGroup DestinationPath="\" SourcePath="." Include="XboxClient.exe"/>
</Chunk>
<Chunk Id="1001">
<FileGroup DestinationPath="\" SourcePath="." Include="fmod.dll"/>
<FileGroup DestinationPath="\" SourcePath="." Include="Microsoft.Xbox.Services.dll"/>
<FileGroup DestinationPath="\" SourcePath="." Include="Microsoft.Xbox.GameChat.dll"/>
<FileGroup DestinationPath="\" SourcePath="." Include="Microsoft.Xbox.Samples.NetworkMesh.dll"/>
</Chunk>
<Chunk Id="1002">
<FileGroup DestinationPath="\" SourcePath="." Include="*.bin"/>
<FileGroup DestinationPath="\" SourcePath="." Include="*.rbxl"/>
<FileGroup DestinationPath="\" SourcePath="." Include="resources.pri"/>
<FileGroup DestinationPath="\" SourcePath="." Include="fflags.json"/>
</Chunk>
<PlaceHolder/>
<!--
Every layout should contain a "padding chunk" with Id="1073741823".
The actual chunk will contain a small, one-byte file
-->
<Chunk Id="1073741823" Marker="Launch">
<FileGroup DestinationPath="\" SourcePath="." Include="Update.alignmentchunk"/>
</Chunk>
</Package>
+2
View File
@@ -0,0 +1,2 @@
xbdel XS:\NSAL.json
xbdel XS:\enforceNSAL
+2
View File
@@ -0,0 +1,2 @@
xbcp NSAL.json XS:\NSAL.json
xbcp enforceNSAL XS:\enforceNSAL
@@ -0,0 +1,6 @@
mklink /D %~dp0\Durango\Layout\Image\Loose\content %~dp0\..\content
mklink /D %~dp0\Durango\Layout\Image\Loose\PlatformContent %~dp0\..\PlatformContent
mklink /D %~dp0\Durango\Layout\Image\Loose\shaders %~dp0\..\shaders
pause
+162
View File
@@ -0,0 +1,162 @@
#include "UserTranslator.h"
#include "util/Http.h"
#include "v8xml/WebParser.h"
#include "rbx/make_shared.h"
extern void dprintf( const char* fmt, ... );
static std::string constructJsonRequest(const UserIDTranslator::GametagSet& tags)
{
if (!tags.empty())
{
std::string requestIds = "{\"ids\":[\"";
bool noComma = true;
for(UserIDTranslator::GametagSet::const_iterator inputIt = tags.begin(); inputIt != tags.end(); ++inputIt)
{
if (noComma)
noComma = false;
else
requestIds += "\",\"";
requestIds += *inputIt;
}
requestIds += "\"]}";
return requestIds;
}
return "";
}
UserIDTranslator::~UserIDTranslator()
{
for(EntryMap::iterator it = entryMap.begin(); it != entryMap.end(); ++it)
{
delete it->second;
}
entryMap.clear();
}
void UserIDTranslator::get( OutputVector& result, const InputVector& inputs )
{
GametagSet gamerTagsToConvert;
if (1)
{
RBX::mutex::scoped_lock lock(requestMutex);
result.clear();
for(InputVector::const_iterator inputIt = inputs.begin(); inputIt != inputs.end(); ++inputIt)
{
std::string xuid = std::string(*inputIt);
Entry* entry = entryMap[xuid];
if (!entry)
{
entry = entryMap[xuid] = new Entry(*inputIt);
gamerTagsToConvert.insert(xuid);
}
else
{
switch (entry->getState())
{
case UserIDTranslator::UnknownUser: // lets try again
case UserIDTranslator::Failed:
gamerTagsToConvert.insert(xuid);
entry->state.store((int)Waiting);
break;
case UserIDTranslator::Ready: // Horray! do nothing
case UserIDTranslator::Waiting: // Still waiting for response, do notning
break;
}
}
result.push_back(entry);
}
}
if (!gamerTagsToConvert.empty())
{
std::string request = constructJsonRequest(gamerTagsToConvert);
RBX::Http( apiUrl ).post(request, RBX::Http::kContentTypeApplicationJson, false,
[this, gamerTagsToConvert](std::string* response, std::exception* exception) mutable
{
if (exception)
dprintf("%s\n", exception->what());
if (response)
{
shared_ptr<const RBX::Reflection::ValueTable> jsonResult(rbx::make_shared<const RBX::Reflection::ValueTable>());
bool parseResult = RBX::WebParser::parseJSONTable(*response, jsonResult);
RBX::Reflection::ValueTable::const_iterator itUsers = jsonResult->find("Users");
if (itUsers != jsonResult->end() && itUsers->second.isType<shared_ptr<const RBX::Reflection::ValueArray> >())
{
shared_ptr<const RBX::Reflection::ValueArray> entries = itUsers->second.cast<shared_ptr<const RBX::Reflection::ValueArray> >();
for(RBX::Reflection::ValueArray::const_iterator it = entries->begin(); it != entries->end(); ++it)
{
if(!it->isType<shared_ptr<const RBX::Reflection::ValueTable> >())
continue;
shared_ptr<const RBX::Reflection::ValueTable> keyValueEntry = it->cast<shared_ptr<const RBX::Reflection::ValueTable> >();
RBX::Reflection::ValueTable::const_iterator itGamertag = keyValueEntry->find("Id");
RBX::Reflection::ValueTable::const_iterator itUserId = keyValueEntry->find("UserId");
if(itGamertag == keyValueEntry->end() || itUserId == keyValueEntry->end())
{
dprintf("UserTranslator: problem decoding part of JSON response\n");
continue;
}
std::string gamertag = "";
if (itGamertag->second.isString())
{
gamertag = itGamertag->second.cast<std::string>();
gamerTagsToConvert.erase(gamertag);
EntryMap::const_iterator it = entryMap.find(gamertag);
if( it != entryMap.end() )
{
Entry* entry = it->second;
if (!itUserId->second.isNumber())
{
entry->state.store(UnknownUser);
}
else
{
entry->robloxUid = itUserId->second.cast<int>();
entry->state.store(Ready);
}
}
}
}
}
}
// set values of gamer tags that were expected to come, but was not send or received
for(boost::unordered_set<std::string>::const_iterator inputIt = gamerTagsToConvert.begin(); inputIt != gamerTagsToConvert.end(); ++inputIt)
{
entryMap[*inputIt]->state.store(Failed);
}
}, false);
}
}
void UserIDTranslator::waitForUIDs( const std::vector< const UserIDTranslator::Entry* >& uids )
{
for (int k=0;;k=0)
{
for (int j=0; j<uids.size(); ++j)
{
auto st = uids[j]->getState();
k += st != UserIDTranslator::Waiting;
}
if( k == uids.size() ) return;
Sleep(5);
}
}
+58
View File
@@ -0,0 +1,58 @@
#pragma once
#include <atomic>
#include <vector>
#include "boost\unordered_map.hpp"
#include "boost/unordered/unordered_set.hpp"
#include "rbx/threadsafe.h"
class UserIDTranslator
{
public:
enum ResultState
{
Waiting = 0,
Ready,
Failed,
UnknownUser
};
struct Entry
{
friend class UserIDTranslator;
std::string gamertag;
int robloxUid;
ResultState getState() const { return (ResultState)state.load(); }
private:
std::atomic<int> state;
Entry():
robloxUid(0),
state(Waiting){}
Entry(const std::string& gamertag)
: gamertag(gamertag)
, state(Waiting) {}
};
typedef std::vector<const Entry*> OutputVector;
typedef std::vector<std::string> InputVector;
typedef boost::unordered_set<std::string> GametagSet;
UserIDTranslator(const std::string& apiUrl_): apiUrl(apiUrl_) {}
~UserIDTranslator();
void get( OutputVector& result, const InputVector& inputs );
static void waitForUIDs( const std::vector< const UserIDTranslator::Entry* >& uids );
private:
std::string apiUrl; // https://api.watrbx.wtf/xbox/translate
typedef boost::unordered_map<std::string, Entry*> EntryMap;
EntryMap entryMap;
RBX::mutex requestMutex; // taken only during get()
};
+362
View File
@@ -0,0 +1,362 @@
#include "VoiceChat.h"
#include "XboxUtils.h"
#include "rbx/Debug.h"
#include "async.h"
#include <map>
#if defined(RBX_PLATFORM_DURANGO)
void dprintf( const char* fmt, ... );
#endif
using namespace Microsoft::Xbox::Services::Multiplayer;
namespace RBX
{
VoiceChat::VoiceChat(unsigned char sessionConsoleId)
: currentUser(nullptr)
{
chatManager = ref new Microsoft::Xbox::GameChat::ChatManager();
chatManager->ChatSettings->AudioThreadPeriodInMilliseconds = 40;
bool dropOutOfOrderPackets = false;
std::string whateverName = "whatever";
try
{
networkMesh = ref new Microsoft::Xbox::Samples::NetworkMesh::MeshManager(sessionConsoleId, "MultiplayerUdp", ref new Platform::String(s2ws(&whateverName).data()), dropOutOfOrderPackets);
}
catch (Platform::Exception^ ex)
{
HRESULT hr = ex->HResult;
const WCHAR* ps = ex->Message->Data();
std::string string = ws2s(ps);
dprintf("Cannot init network mesh: %s", string.c_str());
}
}
VoiceChat::~VoiceChat()
{
Windows::Xbox::System::User::AudioDeviceAdded -= onAudioAdded;
Windows::Xbox::System::User::AudioDeviceAdded -= onAudioRemoved;
if( chatManager != nullptr )
{
chatManager->OnDebugMessage -= onDebugMessageEvtToken;
chatManager->OnOutgoingChatPacketReady -= onOutgoingChatPacketReadyEvtToken;
chatManager->OnCompareUniqueConsoleIdentifiers -= onCompareUniqueConsoleIdentifiersEvtToken;
Windows::ApplicationModel::Core::CoreApplication::ResourceAvailabilityChanged -= onResourceAvailabilityChangedEvtToken;
chatManager = nullptr;
}
if ( networkMesh != nullptr)
{
networkMesh->GetMeshPacketManager()->OnChatMessageReceived -= onChatMessageEvtToken;
networkMesh->OnPostHandshake -= onMeshConnectionAddedEvtToken;
networkMesh->OnDisconnected -= onDisconnectedEvtToken;
networkMesh->Shutdown();
networkMesh = nullptr;
}
}
void VoiceChat::init()
{
boost::weak_ptr<VoiceChat> weakPtrToThis = shared_from_this();
if (networkMesh)
{
onChatMessageEvtToken = networkMesh->GetMeshPacketManager()->OnChatMessageReceived += ref new Windows::Foundation::EventHandler<Microsoft::Xbox::Samples::NetworkMesh::MeshChatMessageReceivedEvent^>(
[weakPtrToThis]( Platform::Object^, Microsoft::Xbox::Samples::NetworkMesh::MeshChatMessageReceivedEvent^ args )
{
Windows::Storage::Streams::IBuffer^ chatPacket = args->Buffer;
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
sharedPtrToThis->onIncomingChatMessage(chatPacket, args->Sender->GetAssociation());
});
onMeshConnectionAddedEvtToken = networkMesh->OnPostHandshake += ref new Windows::Foundation::EventHandler<Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^>(
[weakPtrToThis]( Platform::Object^, Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ args )
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
sharedPtrToThis->onMeshConnectionAdded(args);
});
onDisconnectedEvtToken = networkMesh->OnDisconnected += ref new Windows::Foundation::EventHandler<Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^>(
[weakPtrToThis]( Platform::Object^, Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ args )
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
sharedPtrToThis->onMeshConnectionRemoved(args);
});
}
onOutgoingChatPacketReadyEvtToken = chatManager->OnOutgoingChatPacketReady += ref new Windows::Foundation::EventHandler<Microsoft::Xbox::GameChat::ChatPacketEventArgs^>(
[weakPtrToThis] ( Platform::Object^, Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args )
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
sharedPtrToThis->onOutgoingChatPacketReady(args);
}
});
onDebugMessageEvtToken = chatManager->OnDebugMessage += ref new Windows::Foundation::EventHandler<Microsoft::Xbox::GameChat::DebugMessageEventArgs^>(
[weakPtrToThis] ( Platform::Object^, Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args )
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
sharedPtrToThis->onDebugMessageReceived(args);
});
onCompareUniqueConsoleIdentifiersEvtToken = chatManager->OnCompareUniqueConsoleIdentifiers += ref new Microsoft::Xbox::GameChat::CompareUniqueConsoleIdentifiersHandler(
[weakPtrToThis] ( Platform::Object^ obj1, Platform::Object^ obj2 )
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
Windows::Xbox::Networking::SecureDeviceAssociation^ sda1 = dynamic_cast<Windows::Xbox::Networking::SecureDeviceAssociation^>(obj1);
Windows::Xbox::Networking::SecureDeviceAssociation^ sda2 = dynamic_cast<Windows::Xbox::Networking::SecureDeviceAssociation^>(obj2);
if( sda1 != nullptr && sda2 != nullptr && sda1->RemoteSecureDeviceAddress != nullptr && sda2->RemoteSecureDeviceAddress != nullptr && sda1->RemoteSecureDeviceAddress->Compare(sda2->RemoteSecureDeviceAddress) == 0 )
{
return true;
}
}
return false;
});
onAudioAdded = Windows::Xbox::System::User::AudioDeviceAdded += ref new Windows::Foundation::EventHandler<Windows::Xbox::System::AudioDeviceAddedEventArgs^>(
[weakPtrToThis] (Platform::Object^,Windows::Xbox::System:: AudioDeviceAddedEventArgs^ args)
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
if (args->AudioDevice->Sharing == Windows::Xbox::System::AudioDeviceSharing::Exclusive &&
args->AudioDevice->DeviceType == Windows::Xbox::System::AudioDeviceType::Capture)
{
sharedPtrToThis->headsetConnected(args->User);
}
}
});
onAudioRemoved = Windows::Xbox::System::User::AudioDeviceRemoved += ref new Windows::Foundation::EventHandler<Windows::Xbox::System::AudioDeviceRemovedEventArgs^>(
[weakPtrToThis, this] (Platform::Object^,Windows::Xbox::System:: AudioDeviceRemovedEventArgs^ args)
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
if (args->AudioDevice->Sharing == Windows::Xbox::System::AudioDeviceSharing::Exclusive &&
args->AudioDevice->DeviceType == Windows::Xbox::System::AudioDeviceType::Capture)
{
sharedPtrToThis->headsetDisconnected();
}
}
});
// Upon enter constrained mode, mute everyone.
// Upon leaving constrained mode, unmute everyone who was previously muted.
onResourceAvailabilityChangedEvtToken = Windows::ApplicationModel::Core::CoreApplication::ResourceAvailabilityChanged += ref new Windows::Foundation::EventHandler< Platform::Object^ >(
[weakPtrToThis] (Platform::Object^, Platform::Object^ )
{
boost::shared_ptr<VoiceChat> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
if (Windows::ApplicationModel::Core::CoreApplication::ResourceAvailability == Windows::ApplicationModel::Core::ResourceAvailability::Constrained)
sharedPtrToThis->muteAll();
else if(Windows::ApplicationModel::Core::CoreApplication::ResourceAvailability == Windows::ApplicationModel::Core::ResourceAvailability::Full)
sharedPtrToThis->unmuteAll();
});
}
void VoiceChat::onMeshConnectionAdded(Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ meshConnection)
{
if(chatManager != nullptr)
chatManager->HandleNewRemoteConsole(meshConnection->GetAssociation());
}
void VoiceChat::onMeshConnectionRemoved(Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ meshConnection)
{
if (chatManager != nullptr)
{
async(chatManager->RemoveRemoteConsoleAsync(meshConnection->GetAssociation())).detach();
}
}
void VoiceChat::multiplayerUserAdded(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member)
{
// not used in this implementation
}
void VoiceChat::multiplayerUserRemoved(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member)
{
// not used in this implementation
}
void VoiceChat::onOutgoingChatPacketReady(Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args)
{
if (networkMesh)
{
if (args->SendPacketToAllConnectedConsoles)
{
// Send the chat packet to all connected consoles
Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^>^ meshMembers = networkMesh->GetConnectionsByType(Microsoft::Xbox::Samples::NetworkMesh::ConnectionStatus::PostHandshake);
for(int i = 0; i < meshMembers->Size; i++)
{
Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ member = meshMembers->GetAt(i);
// The simple network layer in this sample doesn't support SendInOrder, so we are ignoring that
networkMesh->GetMeshPacketManager()->SendChatMessage(member->GetAssociation(), args->PacketBuffer, args->SendReliable);
}
}
else
{
Windows::Xbox::Networking::SecureDeviceAssociation^ targetAssociation = dynamic_cast<Windows::Xbox::Networking::SecureDeviceAssociation^>(args->UniqueTargetConsoleIdentifier);
if (targetAssociation != nullptr)
{
networkMesh->GetMeshPacketManager()->SendChatMessage(targetAssociation, args->PacketBuffer, args->SendReliable);
}
}
}
}
void VoiceChat::onIncomingChatMessage(Windows::Storage::Streams::IBuffer^ chatMessage, Platform::Object^ uniqueRemoteConsoleIdentifier)
{
if(chatManager != nullptr)
{
Microsoft::Xbox::GameChat::ChatMessageType chatMessageType = chatManager->ProcessIncomingChatMessage(chatMessage, uniqueRemoteConsoleIdentifier);
}
}
void VoiceChat::setMuteState(bool muted, Microsoft::Xbox::GameChat::ChatUser^ chatUser)
{
if (chatManager != nullptr && chatUser != nullptr)
if (!muted)
chatManager->UnmuteUserFromAllChannels(chatUser);
else
chatManager->MuteUserFromAllChannels(chatUser);
}
void VoiceChat::muteAll()
{
if (chatManager != nullptr)
chatManager->MuteAllUsersFromAllChannels();
}
void VoiceChat::unmuteAll()
{
if (chatManager != nullptr)
chatManager->UnmuteAllUsersFromAllChannels();
}
void VoiceChat::onDebugMessageReceived(Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args)
{
dprintf("GAMECHAT debug: %s", ws2s(args->Message->Data()).c_str());
}
void VoiceChat::headsetConnected(Windows::Xbox::System::User^ user)
{
addLocalUserToChannel(0, user);
if (chatManager && networkMesh)
{
// this will ignore all members that we didnt establish connection yet. Screw those guys right?
Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^>^ meshMembers = networkMesh->GetConnectionsByType(Microsoft::Xbox::Samples::NetworkMesh::ConnectionStatus::PostHandshake);
for(auto member : meshMembers)
{
chatManager->HandleNewRemoteConsole(member->GetAssociation());
}
}
}
void VoiceChat::headsetDisconnected()
{
localUserHasHeadset = false;
removeLocalUserFromChannel();
}
void VoiceChat::addLocalUserToChannel(uint8 channelIndex, Windows::Xbox::System::User^ user)
{
bool oldHeadserState = localUserHasHeadset;
localUserHasHeadset = false;
if (user)
for (auto audio : user->AudioDevices)
if (audio->Sharing == Windows::Xbox::System::AudioDeviceSharing::Exclusive && audio->DeviceType == Windows::Xbox::System::AudioDeviceType::Capture)
{
localUserHasHeadset = true;
break;
}
if(chatManager != nullptr && (currentUser != user || oldHeadserState != localUserHasHeadset))
{
if (localUserHasHeadset)
{
async(chatManager->AddLocalUserToChatChannelAsync(channelIndex, user)).detach();
currentUser = user;
}
}
}
void VoiceChat::removeLocalUserFromChannel()
{
if(chatManager != nullptr && currentUser != nullptr)
{
async(chatManager->RemoveLocalUserFromChatChannelAsync(0, currentUser)).detach();
currentUser = nullptr;
}
}
void VoiceChat::addConnections(Windows::Foundation::Collections::IVectorView<MultiplayerSessionMember^>^ members)
{
if (chatManager && networkMesh)
{
std::map<Platform::String^, bool> deviceTokenSeenMap;
for( auto member : members )
{
if (member->Status != MultiplayerSessionMemberStatus::Active || member->SecureDeviceAddressBase64->IsEmpty() || member->IsCurrentUser)
continue;
if( deviceTokenSeenMap.find(member->DeviceToken) == deviceTokenSeenMap.end() )
{
deviceTokenSeenMap[member->DeviceToken] = true;
Windows::Xbox::Networking::SecureDeviceAddress^ memberSecureDeviceAddress = Windows::Xbox::Networking::SecureDeviceAddress::FromBase64String( member->SecureDeviceAddressBase64 );
if( networkMesh != nullptr )
networkMesh->ConnectToAddress(memberSecureDeviceAddress, member->Gamertag);
}
}
}
}
void VoiceChat::removeConnections(Windows::Foundation::Collections::IVectorView<MultiplayerSessionMember^>^ members)
{
if (chatManager && networkMesh)
{
std::map<Platform::String^, bool> deviceTokenSeenMap;
for( auto member : members )
{
if (member->Status != MultiplayerSessionMemberStatus::Active || member->SecureDeviceAddressBase64->IsEmpty() || member->IsCurrentUser)
continue;
if( deviceTokenSeenMap.find(member->DeviceToken) == deviceTokenSeenMap.end() )
{
deviceTokenSeenMap[member->DeviceToken] = true;
Windows::Xbox::Networking::SecureDeviceAddress^ memberSecureDeviceAddress = Windows::Xbox::Networking::SecureDeviceAddress::FromBase64String( member->SecureDeviceAddressBase64 );
if( networkMesh != nullptr )
networkMesh->DisconectFromAddress(memberSecureDeviceAddress);
}
}
}
}
}
+77
View File
@@ -0,0 +1,77 @@
#pragma once
#include <boost/enable_shared_from_this.hpp>
#include <collection.h>
#include "VoiceChatBase.h"
namespace RBX
{
class VoiceChat : public boost::enable_shared_from_this<VoiceChat>, public VoiceChatBase
{
private:
VoiceChat(unsigned char sessionConsoleId);
public:
static boost::shared_ptr<VoiceChatBase> create(unsigned char sessionConsoleId)
{
boost::shared_ptr<VoiceChat> sp(new VoiceChat(sessionConsoleId));
sp->init();
return sp;
}
virtual ~VoiceChat();
// local user
virtual void addLocalUserToChannel(uint8 channelIndex, Windows::Xbox::System::User^ user);
virtual void removeLocalUserFromChannel();
// remote users
virtual void addConnections(Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^>^ members);
virtual void removeConnections(Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^>^ members);
void onMeshConnectionAdded(Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ meshConnection);
void onMeshConnectionRemoved(Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ meshConnection);
// remote users
virtual void multiplayerUserAdded(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member);
virtual void multiplayerUserRemoved(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member);
// receive/send
void onIncomingChatMessage(Windows::Storage::Streams::IBuffer^ chatMessage, Platform::Object^ uniqueRemoteConsoleIdentifier);
void onOutgoingChatPacketReady(Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args);
void onDebugMessageReceived(Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args);
// muting
virtual void setMuteState(bool muted, Microsoft::Xbox::GameChat::ChatUser^ chatUser);
virtual void muteAll();
virtual void unmuteAll();
private:
void init();
typedef Platform::Box<unsigned int> ConsoleId;
Microsoft::Xbox::GameChat::ChatManager^ chatManager;
Windows::Xbox::System::User^ currentUser;
void headsetConnected(Windows::Xbox::System::User^ user);
void headsetDisconnected();
bool localUserHasHeadset;
// This is sample that we are not supposed to use... YOLO :D
Microsoft::Xbox::Samples::NetworkMesh::MeshManager^ networkMesh;
Windows::Foundation::EventRegistrationToken onDebugMessageEvtToken;
Windows::Foundation::EventRegistrationToken onOutgoingChatPacketReadyEvtToken;
Windows::Foundation::EventRegistrationToken onCompareUniqueConsoleIdentifiersEvtToken;
Windows::Foundation::EventRegistrationToken onResourceAvailabilityChangedEvtToken;
Windows::Foundation::EventRegistrationToken onAudioAdded;
Windows::Foundation::EventRegistrationToken onAudioRemoved;
Windows::Foundation::EventRegistrationToken onChatMessageEvtToken;
Windows::Foundation::EventRegistrationToken onMeshConnectionAddedEvtToken;
Windows::Foundation::EventRegistrationToken onDisconnectedEvtToken;
};
}
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#include "v8datamodel/PlatformService.h"
#include <boost/enable_shared_from_this.hpp>
#include <collection.h>
namespace RBX
{
class VoiceChatBase
{
public:
virtual ~VoiceChatBase(){}
enum TalkingDelta
{
TalkingChange_Start,
TalkingChange_End,
TalkingChange_NoChange
};
// local user
virtual void addLocalUserToChannel(uint8 channelIndex, Windows::Xbox::System::User^ user) = 0;
virtual void removeLocalUserFromChannel() = 0;
// remote users
virtual void addConnections(Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^>^ members) = 0;
virtual void removeConnections(Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^>^ members) = 0;
// remote users
virtual void multiplayerUserAdded(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member) = 0;
virtual void multiplayerUserRemoved(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member) = 0;
// muting
virtual void setMuteState(bool muted, Microsoft::Xbox::GameChat::ChatUser^ chatUser) = 0;
virtual unsigned getMuteState(unsigned memberId) { return (unsigned)VoiceChatState::voiceChatState_Available; }
virtual void muteAll() = 0;
virtual void unmuteAll() = 0;
virtual void muteUser(unsigned memberId){}
virtual void unmuteUser(unsigned memberId){}
virtual void updateMember(unsigned memberId, float distance, TalkingDelta* talkingDeltaOut){}
private:
};
}
+535
View File
@@ -0,0 +1,535 @@
#include "VoiceChatMaxNet.h"
#include "XboxUtils.h"
#include "rbx/Debug.h"
#include "async.h"
#include "g3d/g3dmath.h"
#include <map>
#if defined(RBX_PLATFORM_DURANGO)
void dprintf( const char* fmt, ... );
#endif
using namespace Microsoft::Xbox::Services::Multiplayer;
using namespace Windows::Storage::Streams;
using namespace Microsoft::WRL;
namespace RBX
{
VoiceChatMaxNet::VoiceChatMaxNet(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ currentUser, XboxLiveContext^ xboxLiveContext)
: xbLiveContext(xboxLiveContext)
{
chatManager = ref new Microsoft::Xbox::GameChat::ChatManager();
chatManager->ChatSettings->AudioThreadPeriodInMilliseconds = 40;
chatManager->ChatSettings->AudioThreadAffinityMask = 0xff;
network.reset(new Xp2p::Network(currentUser));
}
VoiceChatMaxNet::~VoiceChatMaxNet()
{
Windows::Xbox::System::User::AudioDeviceAdded -= onAudioAdded;
Windows::Xbox::System::User::AudioDeviceRemoved -= onAudioRemoved;
if( chatManager != nullptr )
{
chatManager->OnDebugMessage -= onDebugMessageEvtToken;
chatManager->OnOutgoingChatPacketReady -= onOutgoingChatPacketReadyEvtToken;
chatManager->OnCompareUniqueConsoleIdentifiers -= onCompareUniqueConsoleIdentifiersEvtToken;
Windows::ApplicationModel::Core::CoreApplication::ResourceAvailabilityChanged -= onResourceAvailabilityChangedEvtToken;
chatManager = nullptr;
}
}
void VoiceChatMaxNet::init()
{
boost::weak_ptr<VoiceChatMaxNet> weakPtrToThis = shared_from_this();
onOutgoingChatPacketReadyEvtToken = chatManager->OnOutgoingChatPacketReady += ref new Windows::Foundation::EventHandler<Microsoft::Xbox::GameChat::ChatPacketEventArgs^>(
[weakPtrToThis] ( Platform::Object^, Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args )
{
boost::shared_ptr<VoiceChatMaxNet> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
sharedPtrToThis->onOutgoingChatPacketReady(args);
}
});
onDebugMessageEvtToken = chatManager->OnDebugMessage += ref new Windows::Foundation::EventHandler<Microsoft::Xbox::GameChat::DebugMessageEventArgs^>(
[weakPtrToThis] ( Platform::Object^, Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args )
{
boost::shared_ptr<VoiceChatMaxNet> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
sharedPtrToThis->onDebugMessageReceived(args);
});
onCompareUniqueConsoleIdentifiersEvtToken = chatManager->OnCompareUniqueConsoleIdentifiers += ref new Microsoft::Xbox::GameChat::CompareUniqueConsoleIdentifiersHandler(
[weakPtrToThis] ( Platform::Object^ obj1, Platform::Object^ obj2 )
{
boost::shared_ptr<VoiceChatMaxNet> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
RBXASSERT(dynamic_cast<ConsoleId^>(obj1) != nullptr);
RBXASSERT(dynamic_cast<ConsoleId^>(obj2) != nullptr);
return (obj1->Equals(obj2));
}
else
return false;
});
// Upon enter constrained mode, mute everyone.
// Upon leaving constrained mode, unmute everyone who was previously muted.
onResourceAvailabilityChangedEvtToken = Windows::ApplicationModel::Core::CoreApplication::ResourceAvailabilityChanged += ref new Windows::Foundation::EventHandler< Platform::Object^ >(
[weakPtrToThis] (Platform::Object^, Platform::Object^ )
{
boost::shared_ptr<VoiceChatMaxNet> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
if (Windows::ApplicationModel::Core::CoreApplication::ResourceAvailability == Windows::ApplicationModel::Core::ResourceAvailability::Constrained)
sharedPtrToThis->muteAll();
else if(Windows::ApplicationModel::Core::CoreApplication::ResourceAvailability == Windows::ApplicationModel::Core::ResourceAvailability::Full)
sharedPtrToThis->unmuteAll();
});
onAudioAdded = Windows::Xbox::System::User::AudioDeviceAdded += ref new Windows::Foundation::EventHandler<Windows::Xbox::System::AudioDeviceAddedEventArgs^>(
[weakPtrToThis, this] (Platform::Object^,Windows::Xbox::System:: AudioDeviceAddedEventArgs^ args)
{
boost::shared_ptr<VoiceChatMaxNet> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
if (args->AudioDevice->Sharing == Windows::Xbox::System::AudioDeviceSharing::Exclusive && args->AudioDevice->DeviceType == Windows::Xbox::System::AudioDeviceType::Capture)
{
RBX::mutex::scoped_lock lock(peersLock);
sharedPtrToThis->subscribeToChatMessages_NoLock();
sharedPtrToThis->headsetConnected(args->User);
}
}
});
onAudioRemoved = Windows::Xbox::System::User::AudioDeviceRemoved += ref new Windows::Foundation::EventHandler<Windows::Xbox::System::AudioDeviceRemovedEventArgs^>(
[weakPtrToThis, this] (Platform::Object^,Windows::Xbox::System:: AudioDeviceRemovedEventArgs^ args)
{
boost::shared_ptr<VoiceChatMaxNet> sharedPtrToThis(weakPtrToThis.lock());
if( sharedPtrToThis != nullptr )
{
RBX::mutex::scoped_lock lock(peersLock);
if (args->AudioDevice->Sharing == Windows::Xbox::System::AudioDeviceSharing::Exclusive && args->AudioDevice->DeviceType == Windows::Xbox::System::AudioDeviceType::Capture)
sharedPtrToThis->unsubscribeToChatMessages_NoLock();
}
});
boost::thread([weakPtrToThis]()
{
while (boost::shared_ptr<VoiceChatMaxNet> sharedPtrToThis = weakPtrToThis.lock() )
{
sharedPtrToThis->receive();
Sleep(30);
}
}).detach();
}
void VoiceChatMaxNet::updateMember(unsigned memberId, float distance, TalkingDelta* talkingDeltaOut)
{
if (chatManager)
for (auto user : chatManager->GetChatUsers())
{
Xp2p::PeerPtr peer = peers[memberId];
if (user->UniqueConsoleIdentifier && peer.get())
{
ConsoleId^ conId = dynamic_cast<ConsoleId^>(user->UniqueConsoleIdentifier);
TalkingState^ currentTalkState = dynamic_cast<TalkingState^>(peer->userObject);
RBXASSERT(conId != nullptr && currentTalkState != nullptr);
bool isTalkingNow = user->NumberOfPendingAudioPacketsToPlay > 0;
if (currentTalkState->Value != isTalkingNow)
{
*talkingDeltaOut = isTalkingNow ? TalkingChange_Start : TalkingChange_End;
peer->userObject = ref new TalkingState(isTalkingNow);
}
else
*talkingDeltaOut = TalkingChange_NoChange;
if (!user->IsMuted)
{
if (user->GetAllChannels()->Size > 0 && user->GetAllChannels()->GetAt(0) == 0)
{
ConsoleId^ conId = dynamic_cast<ConsoleId^>(user->UniqueConsoleIdentifier);
if (conId != nullptr && (unsigned)conId->Value == memberId)
{
static const float fadeOutDistance = 100; // last distance[studs] that you hear fully
static const float slopeInv = 160; // sounds decreases from fadeOutDistance to (fadeOutDistance + slope) to complete zero
user->Volume = G3D::clamp(((fadeOutDistance - distance) / slopeInv) + 1, 0, 1);
break;
}
}
else
user->Volume = 1;
}
else
user->Volume = 0;
}
}
}
void VoiceChatMaxNet::handleNewRemoteConnection(ConsoleId^ consoleId)
{
chatManager->HandleNewRemoteConsole(consoleId);
}
void VoiceChatMaxNet::multiplayerUserAdded(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member)
{
RBX::mutex::scoped_lock lock(peersLock);
RBXASSERT(peers.find(member->MemberId) == peers.end());
if (peers.find(member->MemberId) == peers.end())
{
boost::weak_ptr<VoiceChatMaxNet> weakPtrToThis = shared_from_this();
if (member->Status == MultiplayerSessionMemberStatus::Active && !member->SecureDeviceAddressBase64->IsEmpty() && !member->IsCurrentUser)
{
Microsoft::Xbox::GameChat::ChatUser^ localUser;
for(auto user : chatManager->GetChatUsers())
if (user->IsLocal)
{
localUser = user;
break;
}
RBXASSERT(localUser);
if (!localUser)
return;
peers[member->MemberId] = network->createPeer(member,
[weakPtrToThis, localUser, this](Xp2p::PeerPtr peer)
{
peer->userObject = ref new TalkingState(false);
boost::shared_ptr<VoiceChatMaxNet> voiceChat = weakPtrToThis.lock();
if (voiceChat != nullptr)
{
for (auto audio : localUser->User->AudioDevices)
{
if (audio->Sharing == Windows::Xbox::System::AudioDeviceSharing::Exclusive && audio->DeviceType == Windows::Xbox::System::AudioDeviceType::Capture)
{
RBX::mutex::scoped_lock lock(peersLock);
voiceChat->handleNewRemoteConnection(ref new ConsoleId(peer->getPeerId()));
voiceChat->subscribeToChatMessages_NoLock();
break;
}
}
}
});
}
}
}
void VoiceChatMaxNet::multiplayerUserRemoved(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member)
{
RBX::mutex::scoped_lock lock(peersLock);
RBXASSERT(peers.find(member->MemberId) != peers.end());
if (peers.find(member->MemberId) != peers.end())
{
network->destroyPeer(peers[member->MemberId]);
peers.erase(member->MemberId);
}
}
void VoiceChatMaxNet::sendData(Xp2p::PeerPtr peer, Windows::Storage::Streams::IBuffer^ buffer, unsigned int flags)
{
if (!peer) return;
VoicePacket packet;
packet.type = PacketType_VoicePacket;
packet.size = sizeof(Xp2p::PacketHeader) + buffer->Length;
ComPtr<IBufferByteAccess> bufferByteAccess;
reinterpret_cast<IInspectable*>(buffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess));
unsigned char* dataPtr;
bufferByteAccess->Buffer(&dataPtr);
memcpy(packet.data, dataPtr, buffer->Length);
Xp2p::NetResult result;
if (peer)
do
{
result = network->sendPacket(peer, &packet, 10, flags);
if (result == Xp2p::Net_Retry)
Sleep(1);
}
while(result == Xp2p::Net_Retry);
}
void VoiceChatMaxNet::onOutgoingChatPacketReady(Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args)
{
if (network.get())
{
unsigned flags = Xp2p::Packet_Default;
flags |= args->SendReliable ? Xp2p::Packet_Reliable : 0;
flags |= args->SendInOrder ? Xp2p::Packet_Ordered : 0;
if (args->SendPacketToAllConnectedConsoles)
{
RBX::mutex::scoped_lock lock(peersLock);
for (auto peer : peers)
{
RBX::mutex::scoped_lock subscriptionLock(subscribedPeersLock);
if (subscibedPeers.find(peer.first) != subscibedPeers.end())
sendData(peer.second, args->PacketBuffer, flags);
}
}
else
{
RBX::mutex::scoped_lock lock(peersLock);
unsigned int memId = dynamic_cast<ConsoleId^>(args->UniqueTargetConsoleIdentifier)->Value;
Xp2p::PeerPtr peer = peers[memId];
sendData(peer, args->PacketBuffer, flags);
}
}
}
void VoiceChatMaxNet::receive()
{
Xp2p::PacketStorage storage;
Xp2p::NetResult res = network->recvPacket(&storage, 1);
if (res == Xp2p::Net_Ok)
{
Xp2p::PeerPtr peer;
do
{
res = network->processPacket(peer, &storage);
if (res == Xp2p::Net_Ok)
{
switch (storage.type)
{
case PacketType_VoicePacket:
{
VoicePacket* packet = reinterpret_cast<VoicePacket*>(&storage);
ConsoleId^ consoleId = ref new ConsoleId(peer->getPeerId());
DataWriter ^writer = ref new DataWriter();
writer->WriteBytes(Platform::ArrayReference<unsigned char>(packet->data, packet->getDataSize()));
IBuffer ^buffer = writer->DetachBuffer();
chatManager->ProcessIncomingChatMessage(buffer, consoleId);
break;
}
case PacketType_ControlPacket:
{
ControlVoicePacket* packet = reinterpret_cast<ControlVoicePacket*>(&storage);
ConsoleId^ consoleId = ref new ConsoleId(peer->getPeerId());
if (packet->subscribe > 0)
{
if (Microsoft::Xbox::GameChat::ChatUser^ user = getUserByMemberId(peer->getPeerId()))
{
boost::weak_ptr<VoiceChatMaxNet> weakPtrToThis = shared_from_this();
async(xbLiveContext->PrivacyService->CheckPermissionWithTargetUserAsync(Microsoft::Xbox::Services::Privacy::PermissionIdConstants::CommunicateUsingVoice, user->XboxUserId)).complete(
[weakPtrToThis, peer](Privacy::PermissionCheckResult^ result)
{
boost::shared_ptr<VoiceChatMaxNet> sharedThis = weakPtrToThis.lock();
if (sharedThis && result->IsAllowed)
{
RBX::mutex::scoped_lock lock(sharedThis->subscribedPeersLock);
sharedThis->subscibedPeers.insert(peer->getPeerId());
}
}).detach();
}
}
else
{
RBX::mutex::scoped_lock lock(subscribedPeersLock);
subscibedPeers.erase(peer->getPeerId());
}
break;
}
default:
RBXASSERT(false);
}
}
if (res == Xp2p::Net_Retry)
Sleep(5);
}
while (res == Xp2p::Net_Retry);
}
}
void VoiceChatMaxNet::setMuteState(bool muted, Microsoft::Xbox::GameChat::ChatUser^ chatUser)
{
if (chatManager != nullptr && chatUser != nullptr)
if (!muted)
chatManager->UnmuteUserFromAllChannels(chatUser);
else
chatManager->MuteUserFromAllChannels(chatUser);
}
unsigned VoiceChatMaxNet::getMuteState(unsigned memberId)
{
if (Microsoft::Xbox::GameChat::ChatUser^ user = getUserByMemberId(memberId))
{
if (subscibedPeers.find(memberId) != subscibedPeers.end())
return user->IsMuted ? VoiceChatState::voiceChatState_Available : VoiceChatState::voiceChatState_Muted;
else
return VoiceChatState::voiceChatState_NotInChat;
}
return VoiceChatState::voiceChatState_UnknownUser;
}
void VoiceChatMaxNet::muteAll()
{
if (chatManager != nullptr)
chatManager->MuteAllUsersFromAllChannels();
}
void VoiceChatMaxNet::unmuteAll()
{
if (chatManager != nullptr)
chatManager->UnmuteAllUsersFromAllChannels();
}
Microsoft::Xbox::GameChat::ChatUser^ VoiceChatMaxNet::getUserByMemberId(unsigned id)
{
if (chatManager)
{
for (auto user : chatManager->GetChatUsers())
{
ConsoleId^ conId = dynamic_cast<ConsoleId^>(user->UniqueConsoleIdentifier);
if (conId != nullptr && (unsigned)conId->Value == id)
return user;
}
}
return nullptr;
}
void VoiceChatMaxNet::muteUser(unsigned memberId)
{
if (Microsoft::Xbox::GameChat::ChatUser^ user = getUserByMemberId(memberId))
chatManager->MuteUserFromAllChannels(user);
}
void VoiceChatMaxNet::unmuteUser(unsigned memberId)
{
if (Microsoft::Xbox::GameChat::ChatUser^ user = getUserByMemberId(memberId))
chatManager->UnmuteUserFromAllChannels(user);
}
void VoiceChatMaxNet::onDebugMessageReceived(Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args)
{
dprintf("GAMECHAT debug: %s", ws2s(args->Message->Data()).c_str());
}
void VoiceChatMaxNet::headsetConnected(Windows::Xbox::System::User^ user)
{
addLocalUserToChannel(currentChannel, user);
if (chatManager != nullptr)
{
// this will ignore all members that we didnt establish connection yet. Screw those guys right?
RBX::mutex::scoped_lock lock(peersLock);
for(auto peer : peers)
{
chatManager->HandleNewRemoteConsole(ref new ConsoleId(peer.first));
}
}
}
void VoiceChatMaxNet::addLocalUserToChannel(uint8 channelIndex, Windows::Xbox::System::User^ user)
{
RBX::mutex::scoped_lock lock(channelsLock);
if(chatManager != nullptr && (currentChannel != channelIndex || currentUser != user))
{
async(chatManager->AddLocalUserToChatChannelAsync(channelIndex, user))
.except( [](Platform::Exception^ e) -> void
{
dprintf( "%s exception [0x%x]: %S\n", __FUNCTION__, (int)e->HResult, e->Message->Data() );
})
.join();
removeLocalUserFromChannel_NoLock();
currentChannel = channelIndex;
currentUser = user;
}
}
void VoiceChatMaxNet::removeLocalUserFromChannel()
{
RBX::mutex::scoped_lock lock(channelsLock);
removeLocalUserFromChannel_NoLock();
}
void VoiceChatMaxNet::removeLocalUserFromChannel_NoLock()
{
if(chatManager != nullptr && currentUser != nullptr && currentChannel >= 0 )
{
async(chatManager->RemoveLocalUserFromChatChannelAsync(currentChannel, currentUser))
.except( [](Platform::Exception^ e) -> void
{
dprintf( "%s exception [0x%x]: %S\n", __FUNCTION__, (int)e->HResult, e->Message->Data() );
}).join();
currentChannel = -1;
currentUser = nullptr;
}
}
void VoiceChatMaxNet::addConnections(Windows::Foundation::Collections::IVectorView<MultiplayerSessionMember^>^ members)
{
// we do something smarter in max net
}
void VoiceChatMaxNet::removeConnections(Windows::Foundation::Collections::IVectorView<MultiplayerSessionMember^>^ members)
{
// we do something smarter in max net
}
void VoiceChatMaxNet::unsubscribeToChatMessages_NoLock()
{
for (auto peer : peers)
{
sendVoiceControlPacket(peer.second, false);
}
}
void VoiceChatMaxNet::subscribeToChatMessages_NoLock()
{
for (auto peer : peers)
{
sendVoiceControlPacket(peer.second, true);
}
}
void VoiceChatMaxNet::sendVoiceControlPacket(Xp2p::PeerPtr peer, bool subscribe)
{
if (!peer) return;
ControlVoicePacket packet;
packet.type = PacketType_ControlPacket;
packet.size = sizeof(ControlVoicePacket);
packet.subscribe = subscribe ? 1 : 0;
unsigned flags = Xp2p::Packet_Reliable;
Xp2p::NetResult result;
if (peer)
do
{
result = network->sendPacket(peer, &packet, 10, flags);
if (result == Xp2p::Net_Retry)
Sleep(1);
}
while(result == Xp2p::Net_Retry);
}
}
+123
View File
@@ -0,0 +1,123 @@
#pragma once
#include <boost/enable_shared_from_this.hpp>
#include <collection.h>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <wrl.h>
#include <robuffer.h>
#include <ppl.h>
#include "p2p.h"
#include "rbx/threadsafe.h"
#include "VoiceChatBase.h"
using namespace Microsoft::Xbox::Services;
namespace RBX
{
struct VoicePacket : public Xp2p::PacketHeader
{
unsigned int getDataSize()
{
return size - sizeof(Xp2p::PacketHeader);
}
unsigned char data[Xp2p::PacketStorage::MaxPayloadSize];
};
struct ControlVoicePacket : public Xp2p::PacketHeader
{
uint8 subscribe;
};
class VoiceChatMaxNet : public boost::enable_shared_from_this<VoiceChatMaxNet>, public VoiceChatBase
{
private:
VoiceChatMaxNet(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ currentUser, XboxLiveContext^ xboxLiveContext);
public:
static boost::shared_ptr<VoiceChatBase> create(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ currentUser, XboxLiveContext^ xboxLiveContext)
{
boost::shared_ptr<VoiceChatMaxNet> sp(new VoiceChatMaxNet(currentUser, xboxLiveContext));
sp->init();
return sp;
}
virtual ~VoiceChatMaxNet();
typedef Platform::Box<unsigned int> ConsoleId;
typedef Platform::Box<bool> TalkingState;
// local user
void headsetConnected(Windows::Xbox::System::User^ user);
virtual void addLocalUserToChannel(uint8 channelIndex, Windows::Xbox::System::User^ user);
virtual void removeLocalUserFromChannel();
// remote users
virtual void addConnections(Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^>^ members);
virtual void removeConnections(Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^>^ members);
// remote users
virtual void multiplayerUserAdded(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member);
virtual void multiplayerUserRemoved(Microsoft::Xbox::Services::Multiplayer::MultiplayerSessionMember^ member);
// receive/send
void onOutgoingChatPacketReady(Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args);
void onDebugMessageReceived(Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args);
// muting
virtual void setMuteState(bool muted, Microsoft::Xbox::GameChat::ChatUser^ chatUser);
virtual unsigned getMuteState(unsigned memberId);
virtual void muteAll();
virtual void unmuteAll();
virtual void muteUser(unsigned memberId);
virtual void unmuteUser(unsigned memberId);
virtual void updateMember(unsigned memberId, float distance, TalkingDelta* talkingDeltaOut);
void receive();
void sendVoiceControlPacket(Xp2p::PeerPtr peer, bool subscribe);
void unsubscribeToChatMessages_NoLock();
void subscribeToChatMessages_NoLock();
void handleNewRemoteConnection(ConsoleId^ consoleId);
private:
enum PacketType
{
PacketType_VoicePacket = 1,
PacketType_ControlPacket = 2
};
void init();
void removeLocalUserFromChannel_NoLock();
Microsoft::Xbox::GameChat::ChatUser^ getUserByMemberId(unsigned id);
Microsoft::Xbox::GameChat::ChatManager^ chatManager;
int currentChannel;
Windows::Xbox::System::User^ currentUser;
void sendData(Xp2p::PeerPtr peer, Windows::Storage::Streams::IBuffer^ buffer, unsigned int flags);
boost::scoped_ptr<Xp2p::Network> network;
XboxLiveContext^ xbLiveContext;
RBX::mutex channelsLock;
RBX::mutex peersLock;
RBX::mutex subscribedPeersLock;
boost::unordered_map<unsigned int, Xp2p::PeerPtr> peers;
boost::unordered_set<unsigned int> subscibedPeers;
Windows::Foundation::EventRegistrationToken onDebugMessageEvtToken;
Windows::Foundation::EventRegistrationToken onOutgoingChatPacketReadyEvtToken;
Windows::Foundation::EventRegistrationToken onCompareUniqueConsoleIdentifiersEvtToken;
Windows::Foundation::EventRegistrationToken onResourceAvailabilityChangedEvtToken;
Windows::Foundation::EventRegistrationToken onAudioAdded;
Windows::Foundation::EventRegistrationToken onAudioRemoved;
};
}
+446
View File
@@ -0,0 +1,446 @@
#include "XbLiveUtils.h"
#include <collection.h>
#include "xdpevents.h"
#include <ppltasks.h>
#include <map>
#include "Util/Http.h"
#include "XboxUtils.h"
#include "UserTranslator.h"
#include "async.h"
#include "rbx/make_shared.h"
using namespace Windows::Xbox::Input;
using namespace Windows::Xbox::System;
using namespace Windows::Xbox::UI;
using namespace Windows::Xbox::ApplicationModel::Core;
using namespace Windows::Xbox::Multiplayer;
using namespace Windows::Foundation::Collections;
using namespace Windows::Foundation;
using namespace Microsoft::Xbox::Services;
using namespace Microsoft::Xbox::Services::Presence;
using namespace Microsoft::Xbox::Services::Social;
using namespace Microsoft::Xbox::Services::Privacy;
#define TITLE_ID 0x1465F7BC
#include <map>
int getFriends(std::string* ret, UserIDTranslator* translator, Microsoft::Xbox::Services::XboxLiveContext^ xblContext)
{
bool comma = false;
if( !xblContext || !xblContext->User->IsSignedIn)
{
dprintf("User not signed in, friends are not available.\n");
return -1;
}
XboxLiveContext^ xboxLiveContext = xblContext;
try{
std::vector< Platform::String^ > friendXuids;
IVectorView< XboxUserProfile^ >^ friendProfiles = ref new Platform::Collections::VectorView< XboxUserProfile^ >(); // make sure we it's not null if an exception occurs
IVectorView< PresenceRecord^ >^ friendPresence = ref new Platform::Collections::VectorView< PresenceRecord^ >();
std::vector< std::string > friendGamertags;
std::vector< const UserIDTranslator::Entry* > friendRobloxUids;
try {
// get all favorite people from player's list
async( xboxLiveContext->SocialService->GetSocialRelationshipsAsync()).complete(
[&friendXuids]( XboxSocialRelationshipResult^ result ) -> void
{
for ( auto r : result->Items )
{
if( r->IsFollowingCaller )
friendXuids.push_back( r->XboxUserId );
}
}
).except( [](Platform::Exception^ e) -> void
{
dprintf( "%s exception [0x%x]: %S\n", __FUNCTION__, (int)e->HResult, e->Message->Data() );
}
).join();
if( friendXuids.size() == 0)
{
dprintf("User has no friends.\n");
return -1;
}
// get those people's profiles
auto& a1 = async( xboxLiveContext->ProfileService->GetUserProfilesAsync( ref new Platform::Collections::VectorView< Platform::String^ > ( friendXuids ) ) ).complete(
[&friendProfiles, &friendGamertags]( IVectorView< XboxUserProfile^ > ^ profiles ) -> void
{
friendProfiles = profiles;
for (auto pr : profiles)
{
friendGamertags.push_back(ws2s(pr->Gamertag->Data()));
}
}
);
// get those people's presence
auto& a2 = async( xboxLiveContext->PresenceService->GetPresenceForMultipleUsersAsync( ref new Platform::Collections::VectorView< Platform::String^ >( friendXuids ) ) ).complete(
[&friendPresence]( IVectorView< PresenceRecord^ >^ pr )
{
friendPresence = pr;
}
);
a1.join();
a2.join();
translator->get( friendRobloxUids, friendGamertags );
UserIDTranslator::waitForUIDs(friendRobloxUids); // we've got nothing better to do
}
catch( Platform::Exception^ e )
{
dprintf( "%s exception [0x%x] '%S'. Not an error, but the returned data might be incomplete.\n", __FUNCTION__, (int)e->HResult, e->Message->Data() );
// The function should still generate a well-formed json response string.
// Talk to Max if you're hitting this and the string is not well-formed.
}
// filter out unresolved roblox ids
std::map< std::string, int > rbidLookup;
for( auto e : friendRobloxUids )
{
auto st = e->getState();
if( st == UserIDTranslator::Ready )
rbidLookup[e->gamertag] = e->robloxUid;
}
// not so sure about the order, so...
std::map< std::wstring, std::wstringstream > combined; // xuid -> user info
for ( auto xuid : friendXuids )
combined[xuid->Data()] << L" {\n \"xuid\" : \"" << xuid->Data() << L"\", ";
for ( auto profile : friendProfiles )
{
if ( auto str = mapget( combined, profile->XboxUserId->Data() ) )
{
// Yes, we repeat the gamertag data; this is a quick fix to show gamertag in app instead of display name due to us not wanting
// to fail cert for having unsupported unicode characters.
(*str) << L"\"gamertag\" : \"" << profile->Gamertag->Data() << L"\", " << L"\"display\" : \"" << profile->Gamertag->Data() << L"\", ";
(*str) << L"\"robloxuid\" : ";
if( int robloxuid = rbidLookup[ ws2s(profile->Gamertag->Data()) ] )
(*str) << robloxuid <<", ";
else
(*str) << L"null, ";
}
else
{
dprintf("Warn: got profile for %S, didn\"t ask for.\n", profile->XboxUserId->Data() );
}
}
for ( auto presence : friendPresence )
{
if ( auto str = mapget( combined, presence->XboxUserId->Data() ) )
{
(*str) << L"\"status\" : \"" << presence->UserState.ToString()->Data() << L"\", ";
(*str) << L"\"rich\":\n [\n";
comma = false;
for ( auto r: presence->PresenceTitleRecords )
{
if( comma ) (*str) << ",\n";
(*str) << L" { \"timestamp\" : \"" << r->LastModifiedDate.UniversalTime.ToString()->Data() << "\", \"device\" : \"" << r->DeviceType.ToString()->Data() << "\", \"title\" : \"" << r->TitleName->Data() << "\", \"titleId\" : \"" << r->TitleId.ToString()->Data() << "\" , \"playing\" : \"" << r->IsTitleActive.ToString()->Data() << "\", \"presence\" : \"" << r->Presence->Data() << "\"}";
comma = true;
}
(*str) << L"\n ]\n";
}
else
{
dprintf("Warn: got presence for %S, didn't ask for.\n", presence->XboxUserId->Data() );
}
}
*ret = "{ \"friends\": [\n";
comma = false;
for ( auto& it : combined )
{
it.second << L" }";
if( comma ) *ret += ",\n";
*ret += ws2s( it.second.str().c_str() );
comma = true;
}
*ret += "\n]\n }\n";
return 0;
} catch( Platform::Exception^ e )
{
dprintf( "Friends exception: 0x%x %S\n", e->HResult, e->Message->Data() );
}
return -1;
}
int getParty(std::vector<std::string>* result, bool filter, UserIDTranslator* translator, XboxLiveContext^ xblContext )
{
if(!xblContext||!xblContext->User->IsSignedIn){
dprintf("User not signed in, friends are not available.\n");
return 1;
}
XboxLiveContext^ xboxLiveContext = xblContext;
struct PartyUserInfo
{
Platform::String^ xuid;
Platform::String^ gamertag;
int robloxuid;
int online;
};
std::map< std::string, PartyUserInfo > partyMembers; // xuid->party member info
std::map< std::string, PartyUserInfo* > gtlookup; // gamertag->same party member info
std::vector< Platform::String^ > partyMemberXuids; // list of xbox party members
std::vector< std::string > allgamertags; // list of xbox party members
result->clear();
try
{
// get Xuids of party members
async( PartyChat::GetPartyChatViewAsync() ).complete(
[&]( IPartyChatView^ pv ) -> void
{
if( !pv || !pv->Members )
return;
for( auto mem : pv->Members )
{
std::string xuid = ws2s(mem->XboxUserId->Data());
partyMemberXuids.push_back(mem->XboxUserId);
PartyUserInfo info = {};
info.xuid = mem->XboxUserId;
bool b = partyMembers.insert( std::make_pair(xuid, info) ).second;
if( !b )
{
dprintf("getParty(): got a duplicate xuid [%s] from XBL.\n", xuid.c_str());
}
}
}
).except(
[=](Platform::Exception^ e)
{
dprintf("getParty(): exception 0x%x %S\n", e->HResult, e->Message->Data() );
}
).join();
if( partyMembers.empty() )
{
dprintf("NOTE: getParty(): no party members.\n");
return 1; // no party
}
// look up user profiles to get their gamertags
async( xboxLiveContext->ProfileService->GetUserProfilesAsync( ref new Platform::Collections::VectorView< Platform::String^ > ( partyMemberXuids ) ) ).complete(
[&]( IVectorView< XboxUserProfile^ > ^ profiles ) -> void
{
for( auto pr : profiles )
{
std::string xuid = ws2s( pr->XboxUserId->Data() );
if( PartyUserInfo* info = mapget(partyMembers, xuid) )
{
std::string gamertag = ws2s( pr->Gamertag->Data() );
allgamertags.push_back( gamertag );
info->gamertag = pr->Gamertag;
gtlookup[gamertag] = info;
}
else
{
dprintf("getParty(): got gamertag for [%s], didn't ask for.\n", xuid.c_str() );
}
}
}
).join();
if( !filter )
{
result->swap(allgamertags);
return 0; // done
}
// check that these players are online and have roblox ids
std::vector< const UserIDTranslator::Entry* > robloxuids;
translator->get( robloxuids, allgamertags );
// in parallel, fetch friends' online status
async( xboxLiveContext->PresenceService->GetPresenceForMultipleUsersAsync( ref new Platform::Collections::VectorView< Platform::String^ >( partyMemberXuids ) ) ).complete(
[&]( IVectorView<PresenceRecord^>^ friends )
{
for( auto rec : friends )
{
std::string xuid = ws2s(rec->XboxUserId->Data());
if( PartyUserInfo* info = mapget(partyMembers, xuid) )
{
info->online = rec->UserState == UserPresenceState::Online;
}
else
{
dprintf("getParty(): got presence for [%s], didn't ask for.\n", xuid.c_str());
}
}
}
).join();
UserIDTranslator::waitForUIDs(robloxuids);
// finally, fill out roblox userids
for( int j=0, e=robloxuids.size(); j<e; ++j )
{
auto st = robloxuids[j]->getState();
if( st == UserIDTranslator::Ready )
{
if( PartyUserInfo* info = gtlookup[ robloxuids[j]->gamertag ] )
{
info->robloxuid = robloxuids[j]->robloxUid;
}
else
{
dprintf("getParty(): got Roblox UserId for [%s], didn't ask for.\n", robloxuids[j]->gamertag.c_str() );
}
}
}
// now fill out the result
for( auto& it : partyMembers )
{
auto& info = it.second;
if( info.online && info.robloxuid > 0 )
{
result->push_back(ws2s(info.gamertag->Data()));
}
}
if( result->empty() )
{
dprintf("NOTE: getParty(): all players were filtered out.");
return 1;
}
return 0;
}
catch( Platform::Exception^ e )
{
dprintf( "ERROR: getParty() exception: 0x%x %s\n", e->HResult, e->Message->Data() );
}
return -1;
}
//////////////////////////////////////////////////////////////////////////
// Xbox live events (used for achievements)
void xboxEvents_init()
{
EventRegisterRBLX_1465F7BC();
}
void xboxEvents_shutdown()
{
EventUnregisterRBLX_1465F7BC();
}
static ULONG sendEvent( const ETX_EVENT_DESCRIPTOR* desc, const wchar_t* userId, const GUID* playerSessionId )
{
enum { kNArgs = 3 };
EVENT_DATA_DESCRIPTOR EventData[kNArgs];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (userId != NULL) ? userId : L"", (userId != NULL) ? (ULONG)((wcslen(userId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], playerSessionId, sizeof(GUID));
try{
return EtxEventWrite(desc, &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, kNArgs, EventData);
}catch(Platform::Exception^ e){
dprintf( "%s exception [0x%x]: %S\n", __FUNCTION__, (int)e->HResult, e->Message->Data() );
return 1;
}
}
static ULONG sendEvent( const ETX_EVENT_DESCRIPTOR* desc, const wchar_t* userId, const GUID* playerSessionId, double value)
{
enum { kNArgs = 4 };
EVENT_DATA_DESCRIPTOR EventData[kNArgs];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (userId != NULL) ? userId : L"", (userId != NULL) ? (ULONG)((wcslen(userId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], playerSessionId, sizeof(GUID));
float valFlt = 0;
int valInt = 0;
switch (desc->FieldDescriptors[3].Type)
{
case EtxFieldType_Int32:
{
valInt = (int)value;
EventDataDescCreate(&EventData[3], &valInt, sizeof(int));
break;
}
case EtxFieldType_Float:
{
valFlt = (float)value;
EventDataDescCreate(&EventData[3], &valFlt, sizeof(float));
break;
}
case EtxFieldType_Double:
{
EventDataDescCreate(&EventData[3], &value, sizeof(double));
break;
}
default: RBXASSERT(false); // unsupported type
}
try{
return EtxEventWrite(desc, &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, kNArgs, EventData);
}catch(Platform::Exception^ e){
dprintf( "%s exception [0x%x]: %S\n", __FUNCTION__, (int)e->HResult, e->Message->Data() );
return 1;
}
}
static const ETX_EVENT_DESCRIPTOR* findEvent( const char* name )
{
const ETX_EVENT_DESCRIPTOR* const table = RBLX_1465F7BCEvents;
enum { kCount = sizeof(RBLX_1465F7BCEvents) / sizeof(RBLX_1465F7BCEvents[0]) };
for( int j=0; j<kCount; ++j )
{
if( strcmp( table[j].Name, name ) == 0 )
return &table[j];
}
return 0;
}
RBX::AwardResult xboxEvents_send( Microsoft::Xbox::Services::XboxLiveContext^ xboxLiveContext, const char* evtName, double *value /*= NULL*/)
{
if( !xboxLiveContext ) return RBX::Award_NoUser;
auto e = findEvent(evtName);
if( !e ) return RBX::Award_NotFound;
ULONG r = 1;
if (!value)
r = sendEvent( e, xboxLiveContext->User->XboxUserId->Data(), &IID_IUnknown);
else
r = sendEvent( e, xboxLiveContext->User->XboxUserId->Data(), &IID_IUnknown, *value);
return r == 0 ? RBX::Award_OK : RBX::Award_Fail;
}
+23
View File
@@ -0,0 +1,23 @@
//
// XboxLive stuff
//
// Very toxic, do not include in headers!
//
#include <collection.h>
#include <string>
#include <vector>
#include "v8datamodel/PlatformService.h"
class UserIDTranslator;
class XboxPlatform;
using namespace Microsoft::Xbox::Services;
using namespace Microsoft::Xbox::Services::Multiplayer;
int getFriends(std::string* ret, UserIDTranslator* translator, Microsoft::Xbox::Services::XboxLiveContext^ xboxLiveContext );
int getParty(std::vector<std::string>* result, bool filter, UserIDTranslator* translator, Microsoft::Xbox::Services::XboxLiveContext^ xboxLiveContext);
void xboxEvents_init();
void xboxEvents_shutdown();
RBX::AwardResult xboxEvents_send( Microsoft::Xbox::Services::XboxLiveContext^ xboxLiveContext, const char* evtName, double* value = NULL ); // reentrant
+441
View File
@@ -0,0 +1,441 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Durango">
<Configuration>Debug</Configuration>
<Platform>Durango</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="NoOpt|ARM">
<Configuration>NoOpt</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="NoOpt|Durango">
<Configuration>NoOpt</Configuration>
<Platform>Durango</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Durango">
<Configuration>Release</Configuration>
<Platform>Durango</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A321A726-13A3-4884-ADDA-B0DCCB600765}</ProjectGuid>
<RootNamespace>XboxClient</RootNamespace>
<ApplicationEnvironment>title</ApplicationEnvironment>
<SccProjectName>Perforce Project</SccProjectName>
<SccLocalPath>.</SccLocalPath>
<SccProvider>MSSCCI:Perforce SCM</SccProvider>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='NoOpt|Durango'">
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='NoOpt|ARM'" Label="Configuration">
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<OutDir>bin\$(Configuration)$(Platform)\</OutDir>
<IntDir>obj\$(Configuration)$(Platform)\</IntDir>
<ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkRoot)xdk\fxc\amd64;$(VCInstallDir)bin\x86_amd64;$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(MSBuildToolsPath32);$(FxCopDir);$(PATH);</ExecutablePath>
<IncludePath>$(Console_SdkIncludeRoot)\um;$(Console_SdkIncludeRoot)\shared;$(Console_SdkIncludeRoot)\winrt</IncludePath>
<ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>
<LibraryPath>$(Console_SdkLibPath)</LibraryPath>
<LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<OutDir>bin\$(Configuration)$(Platform)\</OutDir>
<IntDir>obj\$(Configuration)$(Platform)\</IntDir>
<ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkRoot)xdk\fxc\amd64;$(VCInstallDir)bin\x86_amd64;$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(MSBuildToolsPath32);$(FxCopDir);$(PATH);</ExecutablePath>
<IncludePath>$(Console_SdkIncludeRoot)\um;$(Console_SdkIncludeRoot)\shared;$(Console_SdkIncludeRoot)\winrt</IncludePath>
<ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>
<LibraryPath>$(Console_SdkLibPath)</LibraryPath>
<LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='NoOpt|Durango'">
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<OutDir>bin\$(Configuration)$(Platform)\</OutDir>
<IntDir>obj\$(Configuration)$(Platform)\</IntDir>
<ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkRoot)xdk\fxc\amd64;$(VCInstallDir)bin\x86_amd64;$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(MSBuildToolsPath32);$(FxCopDir);$(PATH)</ExecutablePath>
<IncludePath>$(Console_SdkIncludeRoot)\um;$(Console_SdkIncludeRoot)\shared;$(Console_SdkIncludeRoot)\winrt</IncludePath>
<ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>
<LibraryPath>$(Console_SdkLibPath)</LibraryPath>
<LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='NoOpt|ARM'">
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<OutDir>bin\$(Configuration)$(Platform)\</OutDir>
<IntDir>obj\$(Configuration)$(Platform)\</IntDir>
<ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkRoot)xdk\fxc\amd64;$(VCInstallDir)bin\x86_amd64;$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(MSBuildToolsPath32);$(FxCopDir);$(PATH)</ExecutablePath>
<IncludePath>$(Console_SdkIncludeRoot)\um;$(Console_SdkIncludeRoot)\shared;$(Console_SdkIncludeRoot)\winrt</IncludePath>
<ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>
<LibraryPath>$(Console_SdkLibPath)</LibraryPath>
<LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<OutDir>bin\$(Configuration)$(Platform)\</OutDir>
<IntDir>obj\$(Configuration)$(Platform)\</IntDir>
<ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkRoot)xdk\fxc\amd64;$(VCInstallDir)bin\x86_amd64;$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(MSBuildToolsPath32);$(FxCopDir);$(PATH);</ExecutablePath>
<IncludePath>$(Console_SdkIncludeRoot)\um;$(Console_SdkIncludeRoot)\shared;$(Console_SdkIncludeRoot)\winrt</IncludePath>
<ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>
<LibraryPath>$(Console_SdkLibPath)</LibraryPath>
<LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<OutDir>bin\$(Configuration)$(Platform)\</OutDir>
<IntDir>obj\$(Configuration)$(Platform)\</IntDir>
<ExecutablePath>$(Console_SdkRoot)bin;$(Console_SdkRoot)xdk\fxc\amd64;$(VCInstallDir)bin\x86_amd64;$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(MSBuildToolsPath32);$(FxCopDir);$(PATH);</ExecutablePath>
<IncludePath>$(Console_SdkIncludeRoot)\um;$(Console_SdkIncludeRoot)\shared;$(Console_SdkIncludeRoot)\winrt</IncludePath>
<ReferencePath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</ReferencePath>
<LibraryPath>$(Console_SdkLibPath)</LibraryPath>
<LibraryWPath>$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)</LibraryWPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='NoOpt|Durango'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(CONTRIB_PATH)\SDL2\Include;..\ClientBase;$(CONTRIB_PATH)\boost_1_56_0\include;..\Win;..\App\include;..\ClientShared\;..\Base\include;..\Network\include;..\Log\include;..\Rendering\GfxCore\include;..\Rendering\GfxBase\include;..\Rendering\g3d\include;..\Rendering\RbxG3D\include;$(CONTRIB_PATH)\DSBaseClasses\Sources;$(CONTRIB_PATH)\VMProtectWin_2.13;..\fmod\xbox\include;.;..\App.BulletPhysics;$(CONTRIB_PATH)\SDL\SDL2-2.0.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>RBX_PLATFORM_DURANGO;_TITLE;MONOLITHIC=1;WINAPI_FAMILY=WINAPI_FAMILY_TV_TITLE;_NOOPT;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<OmitFramePointers>false</OmitFramePointers>
<ForcedUsingFiles>"C:\Program Files (x86)\Microsoft Durango XDK\xdk\Extensions\Xbox Services API\8.0\References\CommonConfiguration\neutral\Microsoft.Xbox.Services.winmd";%(ForcedUsingFiles)</ForcedUsingFiles>
</ClCompile>
<Link>
<AdditionalDependencies>etwplus.lib;mmdevapi.lib;d3d11_x.lib;xg_x.lib;combase.lib;toolhelpx.lib;D3DCompiler.lib;dxguid.lib;ws2_32.lib;kernelx.lib;zlib.lib;fmod_vc.lib</AdditionalDependencies>
</Link>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>tbb.lib;psapi.lib;version.lib;kernel32.lib;oldnames.lib;runtimeobject.lib;ole32.lib</IgnoreSpecificDefaultLibraries>
<AdditionalLibraryDirectories>..\zlib\win\bin\ReleaseDurango;..\fmod\xbox\lib</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>python fetchfflags.py &gt; $(LayoutDir)Image\Loose\fflags.json
xcopy /b /y $(ProjectDir)img\* $(LayoutDir)Image\Loose\img\
xcopy /b /y $(SolutionDir)fmod\xbox\fmodex.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Debug\Microsoft.Xbox.Samples.NetworkMesh.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Debug\Microsoft.Xbox.Samples.NetworkMesh.pdb "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Debug\Microsoft.Xbox.GameChat.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Debug\Microsoft.Xbox.GameChat.pdb "$(LayoutDir)Image\Loose"
call "$(SolutionDir)buildshaders.bat"
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>..\CoreScriptConverter2\tool\win32\BuildCoreScripts.bat ..\xboxrsc.config</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='NoOpt|ARM'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(CONTRIB_PATH)\SDL2\Include;..\ClientBase;$(CONTRIB_PATH)\boost_1_56_0\include;..\Win;..\App\include;..\ClientShared\;..\Base\include;..\Network\include;..\Log\include;..\Rendering\GfxCore\include;..\Rendering\GfxBase\include;..\Rendering\g3d\include;..\Rendering\RbxG3D\include;$(CONTRIB_PATH)\DSBaseClasses\Sources;$(CONTRIB_PATH)\VMProtectWin_2.13;..\fmod\xbox\include;.;..\App.BulletPhysics;$(CONTRIB_PATH)\SDL\SDL2-2.0.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>RBX_PLATFORM_DURANGO;_TITLE;MONOLITHIC=1;WINAPI_FAMILY=WINAPI_FAMILY_TV_TITLE;_NOOPT;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<OmitFramePointers>false</OmitFramePointers>
<ForcedUsingFiles>"C:\Program Files (x86)\Microsoft Durango XDK\xdk\Extensions\Xbox Services API\8.0\References\CommonConfiguration\neutral\Microsoft.Xbox.Services.winmd";%(ForcedUsingFiles)</ForcedUsingFiles>
</ClCompile>
<Link>
<AdditionalDependencies>etwplus.lib;mmdevapi.lib;d3d11_x.lib;xg_x.lib;combase.lib;toolhelpx.lib;D3DCompiler.lib;dxguid.lib;ws2_32.lib;kernelx.lib;zlib.lib;fmod_vc.lib</AdditionalDependencies>
</Link>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>tbb.lib;psapi.lib;version.lib;kernel32.lib;oldnames.lib;runtimeobject.lib;ole32.lib</IgnoreSpecificDefaultLibraries>
<AdditionalLibraryDirectories>..\zlib\win\bin\ReleaseDurango;..\fmod\xbox\lib</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>python fetchfflags.py &gt; $(LayoutDir)Image\Loose\fflags.json
xcopy /b /y $(ProjectDir)img\* $(LayoutDir)Image\Loose\img\
xcopy /b /y $(SolutionDir)fmod\xbox\fmodex.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Debug\Microsoft.Xbox.Samples.NetworkMesh.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Debug\Microsoft.Xbox.Samples.NetworkMesh.pdb "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Debug\Microsoft.Xbox.GameChat.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Debug\Microsoft.Xbox.GameChat.pdb "$(LayoutDir)Image\Loose"
call "$(SolutionDir)buildshaders.bat"
</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>..\CoreScriptConverter2\tool\win32\BuildCoreScripts.bat ..\xboxrsc.config</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RBX_PLATFORM_DURANGO;_TITLE;MONOLITHIC=1;WINAPI_FAMILY=WINAPI_FAMILY_TV_TITLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(CONTRIB_PATH)\SDL2\Include;..\ClientBase;$(CONTRIB_PATH)\boost_1_56_0\include;..\Win;..\App\include;..\Base\include;..\Network\include;..\Log\include;..\Rendering\GfxCore\include;..\Rendering\GfxBase\include;..\Rendering\g3d\include;..\Rendering\RbxG3D\include;$(CONTRIB_PATH)\DSBaseClasses\Sources;$(CONTRIB_PATH)\VMProtectWin_2.13;..\fmod\xbox\include;.;..\App.BulletPhysics;$(CONTRIB_PATH)\SDL\SDL2-2.0.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>etwplus.lib;mmdevapi.lib;d3d11_x.lib;xg_x.lib;combase.lib;toolhelpx.lib;D3DCompiler.lib;dxguid.lib;etwplus.lib;ws2_32.lib;kernelx.lib;zlib.lib;fmodex_static.lib</AdditionalDependencies>
</Link>
<Link>
<IgnoreSpecificDefaultLibraries>tbb.lib;psapi.lib;version.lib;kernel32.lib;oldnames.lib;runtimeobject.lib;ole32.lib</IgnoreSpecificDefaultLibraries>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>..\zlib\win\bin\ReleaseDurango;..\fmod\xbox</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>python fetchfflags.py &gt; $(LayoutDir)Image\Loose\fflags.json
xcopy /b /y $(ProjectDir)img\* $(LayoutDir)Image\Loose\img\
call "$(SolutionDir)buildshaders.bat"
"$(DurangoXDK)bin\xbcp" NSAL.json XS:\NSAL.json
"$(DurangoXDK)bin\xbcp" enforceNSAL XS:\enforceNSAL</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>..\CoreScriptConverter2\tool\win32\BuildCoreScripts.bat ..\xboxrsc.config</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RBX_PLATFORM_DURANGO;_TITLE;MONOLITHIC=1;WINAPI_FAMILY=WINAPI_FAMILY_TV_TITLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(CONTRIB_PATH)\SDL2\Include;..\ClientBase;$(CONTRIB_PATH)\boost_1_56_0\include;..\Win;..\App\include;..\Base\include;..\Network\include;..\Log\include;..\Rendering\GfxCore\include;..\Rendering\GfxBase\include;..\Rendering\g3d\include;..\Rendering\RbxG3D\include;$(CONTRIB_PATH)\DSBaseClasses\Sources;$(CONTRIB_PATH)\VMProtectWin_2.13;..\fmod\xbox\include;.;..\App.BulletPhysics;$(CONTRIB_PATH)\SDL\SDL2-2.0.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>etwplus.lib;mmdevapi.lib;d3d11_x.lib;xg_x.lib;combase.lib;toolhelpx.lib;D3DCompiler.lib;dxguid.lib;etwplus.lib;ws2_32.lib;kernelx.lib;zlib.lib;fmodex_static.lib</AdditionalDependencies>
</Link>
<Link>
<IgnoreSpecificDefaultLibraries>tbb.lib;psapi.lib;version.lib;kernel32.lib;oldnames.lib;runtimeobject.lib;ole32.lib</IgnoreSpecificDefaultLibraries>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>..\zlib\win\bin\ReleaseDurango;..\fmod\xbox</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>python fetchfflags.py &gt; $(LayoutDir)Image\Loose\fflags.json
xcopy /b /y $(ProjectDir)img\* $(LayoutDir)Image\Loose\img\
call "$(SolutionDir)buildshaders.bat"
"$(DurangoXDK)bin\xbcp" NSAL.json XS:\NSAL.json
"$(DurangoXDK)bin\xbcp" enforceNSAL XS:\enforceNSAL</Command>
</PostBuildEvent>
<PreBuildEvent>
<Command>..\CoreScriptConverter2\tool\win32\BuildCoreScripts.bat ..\xboxrsc.config</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">
<Link>
<AdditionalDependencies>etwplus.lib;mmdevapi.lib;d3d11_x.lib;xg_x.lib;combase.lib;toolhelpx.lib;D3DCompiler.lib;dxguid.lib;ws2_32.lib;kernelx.lib;zlib.lib;fmod_vc.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Link>
<AdditionalDependencies>etwplus.lib;mmdevapi.lib;d3d11_x.lib;xg_x.lib;combase.lib;toolhelpx.lib;D3DCompiler.lib;dxguid.lib;ws2_32.lib;kernelx.lib;zlib.lib;fmod_vc.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">
<Link>
<IgnoreSpecificDefaultLibraries>tbb.lib;psapi.lib;version.lib;kernel32.lib;oldnames.lib;runtimeobject.lib;ole32.lib</IgnoreSpecificDefaultLibraries>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>..\zlib\win\bin\ReleaseDurango;..\fmod\xbox\lib</AdditionalLibraryDirectories>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
</Link>
<PostBuildEvent>
<Command>python fetchfflags.py &gt; $(LayoutDir)Image\Loose\fflags.json
xcopy /b /y $(ProjectDir)img\* $(LayoutDir)Image\Loose\img\
xcopy /b /y $(SolutionDir)fmod\xbox\fmodex.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Release\Microsoft.Xbox.Samples.NetworkMesh.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Release\Microsoft.Xbox.Samples.NetworkMesh.pdb "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Release\Microsoft.Xbox.GameChat.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Release\Microsoft.Xbox.GameChat.pdb "$(LayoutDir)Image\Loose"
call "$(SolutionDir)buildshaders.bat"
</Command>
</PostBuildEvent>
<ClCompile>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(CONTRIB_PATH)\SDL2\Include;..\ClientBase;$(CONTRIB_PATH)\boost_1_56_0\include;..\Win;..\App\include;..\ClientShared\;..\Base\include;..\Network\include;..\Log\include;..\Rendering\GfxCore\include;..\Rendering\GfxBase\include;..\Rendering\g3d\include;..\Rendering\RbxG3D\include;$(CONTRIB_PATH)\DSBaseClasses\Sources;$(CONTRIB_PATH)\VMProtectWin_2.13;..\fmod\xbox\include;.;..\App.BulletPhysics;$(CONTRIB_PATH)\SDL\SDL2-2.0.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>RBX_PLATFORM_DURANGO;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(Console_SdkWindowsMetadataPath)</AdditionalUsingDirectories>
</ClCompile>
<PreBuildEvent>
<Command>..\CoreScriptConverter2\tool\win32\BuildCoreScripts.bat ..\xboxrsc.config</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Link>
<IgnoreSpecificDefaultLibraries>tbb.lib;psapi.lib;version.lib;kernel32.lib;oldnames.lib;runtimeobject.lib;ole32.lib</IgnoreSpecificDefaultLibraries>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>..\zlib\win\bin\ReleaseDurango;..\fmod\xbox\lib</AdditionalLibraryDirectories>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
</Link>
<PostBuildEvent>
<Command>python fetchfflags.py &gt; $(LayoutDir)Image\Loose\fflags.json
xcopy /b /y $(ProjectDir)img\* $(LayoutDir)Image\Loose\img\
xcopy /b /y $(SolutionDir)fmod\xbox\fmodex.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Release\Microsoft.Xbox.Samples.NetworkMesh.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)Microsoft.Xbox.Samples.NetworkMesh\Durango\Release\Microsoft.Xbox.Samples.NetworkMesh.pdb "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Release\Microsoft.Xbox.GameChat.dll "$(LayoutDir)Image\Loose"
xcopy /b /y $(SolutionDir)GameChat\Durango\Release\Microsoft.Xbox.GameChat.pdb "$(LayoutDir)Image\Loose"
call "$(SolutionDir)buildshaders.bat"
</Command>
</PostBuildEvent>
<ClCompile>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(CONTRIB_PATH)\SDL2\Include;..\ClientBase;$(CONTRIB_PATH)\boost_1_56_0\include;..\Win;..\App\include;..\ClientShared\;..\Base\include;..\Network\include;..\Log\include;..\Rendering\GfxCore\include;..\Rendering\GfxBase\include;..\Rendering\g3d\include;..\Rendering\RbxG3D\include;$(CONTRIB_PATH)\DSBaseClasses\Sources;$(CONTRIB_PATH)\VMProtectWin_2.13;..\fmod\xbox\include;.;..\App.BulletPhysics;$(CONTRIB_PATH)\SDL\SDL2-2.0.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>RBX_PLATFORM_DURANGO;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalUsingDirectories>$(Console_SdkWindowsMetadataPath)</AdditionalUsingDirectories>
</ClCompile>
<PreBuildEvent>
<Command>..\CoreScriptConverter2\tool\win32\BuildCoreScripts.bat ..\xboxrsc.config</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\App\script\LuaVMClient.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='NoOpt|Durango'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='NoOpt|ARM'">false</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\App\script\LuaVMDummy.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='NoOpt|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='NoOpt|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\ClientBase\RenderSettingsItem.cpp" />
<ClCompile Include="..\ClientShared\DataModelEmptySerialize.cpp" />
<ClCompile Include="async.cpp" />
<ClCompile Include="ControllerBuffer.cpp" />
<ClCompile Include="fmodstub.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='NoOpt|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='NoOpt|ARM'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="KeyboardProvider.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="marshaller.cpp" />
<ClCompile Include="p2p.cpp" />
<ClCompile Include="renderJob.cpp" />
<ClCompile Include="UserTranslator.cpp" />
<ClCompile Include="VoiceChat.cpp" />
<ClCompile Include="VoiceChatMaxNet.cpp" />
<ClCompile Include="XbLiveUtils.cpp" />
<ClCompile Include="XboxGameController.cpp" />
<ClCompile Include="XboxMultiplayerManager.cpp" />
<ClCompile Include="XboxService.cpp" />
<ClCompile Include="XboxUtils.cpp" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\App.BulletPhysics\App.BulletPhysics.vcxproj">
<Project>{c9285114-dcc1-4e90-aa76-f590cefb94c2}</Project>
</ProjectReference>
<ProjectReference Include="..\App\App.vcxproj">
<Project>{63db8347-940b-4a05-8975-6a6545c315dc}</Project>
</ProjectReference>
<ProjectReference Include="..\Base\Base.vcxproj">
<Project>{3025c00a-7746-469b-a279-96127c72abee}</Project>
</ProjectReference>
<ProjectReference Include="..\boostlibs\boost.static.vcxproj">
<Project>{5423bfb6-d3eb-4b00-a82b-38001eb8745f}</Project>
</ProjectReference>
<ProjectReference Include="..\CSG\CSG.vcxproj">
<Project>{9b6c66f7-6887-44d3-ac5e-3c2bd94661fc}</Project>
</ProjectReference>
<ProjectReference Include="..\GameChat\Microsoft.Xbox.GameChat.XDK.vcxproj">
<Project>{9b399639-7a3f-44cf-82ef-d4c50718130e}</Project>
</ProjectReference>
<ProjectReference Include="..\Log\Log.vcxproj">
<Project>{9980f6c3-b64d-4775-8793-bb6dde31ce82}</Project>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Xbox.Samples.NetworkMesh\Microsoft.Xbox.Samples.NetworkMesh.vcxproj">
<Project>{9b399639-7a3f-44cf-82ef-d4c50718120e}</Project>
<Private>true</Private>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
<ProjectReference Include="..\Network\Network.vcxproj">
<Project>{9b9eb5c6-15d1-4765-bcc7-8a42f2c9f6cc}</Project>
</ProjectReference>
<ProjectReference Include="..\Rendering\AppDraw\AppDraw.vcxproj">
<Project>{43afcf25-5133-4978-8b2c-d02ee0eee199}</Project>
</ProjectReference>
<ProjectReference Include="..\Rendering\g3d\graphics3D.vcxproj">
<Project>{05c08695-1eca-489c-815d-d74d65f353f0}</Project>
</ProjectReference>
<ProjectReference Include="..\Rendering\GfxBase\GfxBase.vcxproj">
<Project>{857de167-1ed8-4e4d-955a-5cc5cc3944c1}</Project>
</ProjectReference>
<ProjectReference Include="..\Rendering\GfxCore\GfxCore.vcxproj">
<Project>{3a10c3ec-1b27-427e-b955-87ee6b176130}</Project>
</ProjectReference>
<ProjectReference Include="..\Rendering\GfxRender\GfxRender.vcxproj">
<Project>{9b7cce5d-2877-4321-8910-3c8e3936f62f}</Project>
</ProjectReference>
<ProjectReference Include="..\Rendering\RbxG3D\RbxG3D.vcxproj">
<Project>{7d55bdab-c90b-4b36-9b2c-af8ef3e9129f}</Project>
</ProjectReference>
<ProjectReference Include="..\zlib\win\zlib.vcxproj">
<Project>{85ff2e31-e863-40cc-b1d6-c6c1875ec5a1}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\ClientBase\RenderSettingsItem.h" />
<ClInclude Include="async.h" />
<ClInclude Include="ControllerBuffer.h" />
<ClInclude Include="KeyboardProvider.h" />
<ClInclude Include="marshaller.h" />
<ClInclude Include="p2p.h" />
<ClInclude Include="renderJob.h" />
<ClInclude Include="UserTranslator.h" />
<ClInclude Include="VoiceChat.h" />
<ClInclude Include="VoiceChatBase.h" />
<ClInclude Include="VoiceChatMaxNet.h" />
<ClInclude Include="XbLiveUtils.h" />
<ClInclude Include="XboxGameController.h" />
<ClInclude Include="XboxMultiplayerManager.h" />
<ClInclude Include="XboxService.h" />
<ClInclude Include="XboxUtils.h" />
<ClInclude Include="xdpevents.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\fmod\xbox\fmod.dll">
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">true</DeploymentContent>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</DeploymentContent>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='NoOpt|Durango'">true</DeploymentContent>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='NoOpt|ARM'">true</DeploymentContent>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</DeploymentContent>
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</DeploymentContent>
</None>
<None Include="NSAL.json" />
<None Include="xdpevents.bat" />
</ItemGroup>
<ItemGroup>
<SDKReference Include="Xbox Services API, Version=8.0" />
</ItemGroup>
<ItemGroup>
<Text Include="xdpevents.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+72
View File
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="..\ClientBase\RenderSettingsItem.cpp">
<Filter>ClientBase</Filter>
</ClCompile>
<ClCompile Include="..\ClientShared\DataModelEmptySerialize.cpp">
<Filter>ClientShared</Filter>
</ClCompile>
<ClCompile Include="XboxGameController.cpp" />
<ClCompile Include="..\App\script\LuaVMClient.cpp" />
<ClCompile Include="renderJob.cpp" />
<ClCompile Include="marshaller.cpp" />
<ClCompile Include="XboxService.cpp" />
<ClCompile Include="XboxUtils.cpp" />
<ClCompile Include="async.cpp" />
<ClCompile Include="ControllerBuffer.cpp" />
<ClCompile Include="UserTranslator.cpp" />
<ClCompile Include="XbLiveUtils.cpp" />
<ClCompile Include="KeyboardProvider.cpp" />
<ClCompile Include="VoiceChat.cpp" />
<ClCompile Include="XboxMultiplayerManager.cpp" />
<ClCompile Include="p2p.cpp" />
<ClCompile Include="..\App\script\LuaVMDummy.cpp" />
<ClCompile Include="fmodstub.cpp" />
<ClCompile Include="VoiceChatMaxNet.cpp" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest" />
</ItemGroup>
<ItemGroup>
<Filter Include="ClientBase">
<UniqueIdentifier>{91536e1d-2944-4a65-89bd-86ea5d84942f}</UniqueIdentifier>
</Filter>
<Filter Include="ClientShared">
<UniqueIdentifier>{c20ed3de-040a-4e8b-94de-11a3b24f3ab5}</UniqueIdentifier>
</Filter>
<Filter Include="Libraries">
<UniqueIdentifier>{db898056-59d7-4be5-9299-25f948c6d53e}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\ClientBase\RenderSettingsItem.h">
<Filter>ClientBase</Filter>
</ClInclude>
<ClInclude Include="XboxGameController.h" />
<ClInclude Include="marshaller.h" />
<ClInclude Include="renderJob.h" />
<ClInclude Include="XboxService.h" />
<ClInclude Include="XboxUtils.h" />
<ClInclude Include="async.h" />
<ClInclude Include="ControllerBuffer.h" />
<ClInclude Include="UserTranslator.h" />
<ClInclude Include="XbLiveUtils.h" />
<ClInclude Include="KeyboardProvider.h" />
<ClInclude Include="xdpevents.h" />
<ClInclude Include="XboxMultiplayerManager.h" />
<ClInclude Include="VoiceChat.h" />
<ClInclude Include="p2p.h" />
<ClInclude Include="VoiceChatMaxNet.h" />
<ClInclude Include="VoiceChatBase.h" />
</ItemGroup>
<ItemGroup>
<None Include="NSAL.json" />
<None Include="xdpevents.bat" />
<None Include="..\fmod\xbox\fmod.dll" />
</ItemGroup>
<ItemGroup>
<Text Include="xdpevents.txt" />
</ItemGroup>
</Project>
+411
View File
@@ -0,0 +1,411 @@
#include "XboxGameController.h"
#include <vector>
#include "reflection/type.h"
#include "v8datamodel/DataModel.h"
#include "v8datamodel/UserInputService.h"
#include "v8datamodel/GamepadService.h"
using namespace boost;
using namespace RBX;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
XboxGameController::XboxGameController(shared_ptr<RBX::DataModel> newDM, shared_ptr<ControllerBuffer> newControllerBuffer) :
controllerBuffer(newControllerBuffer)
{
currentVibration.LeftMotorLevel = 0;
currentVibration.RightMotorLevel = 0;
currentVibration.LeftTriggerLevel = 0;
currentVibration.RightTriggerLevel = 0;
controllerBuffer->setXboxGameController(this);
initializedControllerGuidMap = false;
setDataModel(newDM);
}
void XboxGameController::handleNewGamepad(IGamepad^ gamepad)
{
int rbxGamepadInt = getRbxGamepadIntFromGamepad(gamepad);
if (rbxGamepadInt >= 0)
{
gamepadConnectedMap[rbxGamepadInt].isConnected = true;
gamepadConnectedMap[rbxGamepadInt].guid = gamepad->Id;
fireGamepadConnectedEvent(rbxGamepadInt);
}
}
void XboxGameController::handleGamepadRemove(IGamepad^ gamepad)
{
gamepadConnectedMap.erase(gamepad->Id);
fireGamepadDisconnectedEvent(gamepad->Id);
}
void XboxGameController::setupGamepadHandling()
{
// first clear out all old data
Windows::Xbox::Input::Gamepad::GamepadAdded -= gamepadAddedEvent;
Windows::Xbox::Input::Gamepad::GamepadRemoved -= gamepadRemovedEvent;
gamepadConnectedMap.clear();
// now lets setup all existing gamepads
IVectorView<IGamepad^>^ gamepads = Windows::Xbox::Input::Gamepad::Gamepads;
for ( unsigned int i = 0; i < gamepads->Size; ++i )
{
handleNewGamepad(gamepads->GetAt(i));
}
// finally listen to gamepads being removed and added
gamepadAddedEvent = Windows::Xbox::Input::Gamepad::GamepadAdded += ref new EventHandler<GamepadAddedEventArgs^ >( [=]( Platform::Object^ , GamepadAddedEventArgs^ args )
{
handleNewGamepad(args->Gamepad);
});
gamepadRemovedEvent = Windows::Xbox::Input::Gamepad::GamepadRemoved += ref new EventHandler<GamepadRemovedEventArgs^ >( [=]( Platform::Object^ , GamepadRemovedEventArgs^ args )
{
handleGamepadRemove(args->Gamepad);
});
}
void XboxGameController::resetControllerGuidMap()
{
initializedControllerGuidMap = false;
xboxLiveIdToRBXGamepadType.clear();
}
void XboxGameController::setDataModel(shared_ptr<RBX::DataModel> newDM)
{
dataModel = newDM;
setupGamepadHandling();
if ( RBX::UserInputService* inputService = RBX::ServiceProvider::find<UserInputService>(newDM.get()) )
{
getSupportedGamepadKeyCodesConnection.disconnect();
getSupportedGamepadKeyCodesConnection = inputService->getSupportedGamepadKeyCodesSignal.connect(boost::bind(&XboxGameController::findAvailableGamepadKeyCodesAndSet, this, _1));
updateInputConnection.disconnect();
updateInputConnection = inputService->updateInputSignal.connect(boost::bind(&XboxGameController::processControllerBuffer, this));
}
if ( RBX::HapticService* hapticService = RBX::ServiceProvider::create<HapticService>(newDM.get()) )
{
setEnabledVibrationMotorsConnection.disconnect();
setVibrationMotorConnection.disconnect();
setEnabledVibrationMotorsConnection = hapticService->setEnabledVibrationMotorsSignal.connect(boost::bind(&XboxGameController::setVibrationMotorsEnabled, this, _1));
setVibrationMotorConnection = hapticService->setVibrationMotorSignal.connect(boost::bind(&XboxGameController::setVibrationMotor, this, _1, _2, _3));
}
}
int XboxGameController::getRbxGamepadIntFromGamepad(Windows::Xbox::Input::IGamepad^ gamepad)
{
if (!initializedControllerGuidMap)
{
IVectorView<IGamepad^>^ gamepads = Windows::Xbox::Input::Gamepad::Gamepads;
for ( unsigned int i = 0; i < gamepads->Size; ++i )
{
if (gamepads->GetAt(i) == gamepad)
{
return i;
}
}
return -1;
}
if (gamepad == nullptr)
{
return -1;
}
User^ user = nullptr;
try
{
user = gamepad->User;
}
catch (std::runtime_error)
{
return -1;
}
if (user == nullptr)
{
return -1;
}
Platform::String^ xboxUserId;
try
{
xboxUserId = user->XboxUserId;
}
catch (std::runtime_error)
{
return -1;
}
if (xboxUserId == nullptr)
{
return -1;
}
if (xboxUserId->IsEmpty())
{
return -1;
}
try
{
if (user->IsGuest)
{
return -1;
}
}
catch (std::runtime_error)
{
return -1;
}
RBX::InputObject::UserInputType gamepadEnum = InputObject::TYPE_NONE;
int rbxGamepadInt = 0;
if (!getRBXGamepadFromXboxLiveId(xboxUserId, gamepad->Id, gamepadEnum, rbxGamepadInt))
{
return -1;
}
return rbxGamepadInt;
}
void XboxGameController::remapXboxLiveIdToRBXGamepadId(Platform::String^ xboxLiveId, unsigned long long controllerId, RBX::InputObject::UserInputType gamepadType)
{
// todo: actually do remapping instead of blowing away mapping and adding one in (need this now for xbox cert)
xboxLiveIdToRBXGamepadType.clear();
std::pair<Platform::String^,unsigned long long> liveIdControllerIdPair(xboxLiveId,controllerId);
xboxLiveIdToRBXGamepadType[liveIdControllerIdPair] = gamepadType;
initializedControllerGuidMap = true;
}
bool XboxGameController::getRBXGamepadFromXboxLiveId(Platform::String^ xboxLiveId, unsigned long long controllerId, RBX::InputObject::UserInputType& gamepadEnum, int& rbxGamepadInt)
{
std::pair<Platform::String^,unsigned long long> liveIdControllerIdPair(xboxLiveId, controllerId);
std::map<std::pair<Platform::String^, unsigned long long>, RBX::InputObject::UserInputType>::iterator iter = xboxLiveIdToRBXGamepadType.find(liveIdControllerIdPair);
if (iter == xboxLiveIdToRBXGamepadType.end())
{
return false;
}
gamepadEnum = iter->second;
rbxGamepadInt = RBX::GamepadService::getGamepadIntForEnum(gamepadEnum);
return true;
}
void XboxGameController::updateVibration()
{
const uint64 gamepadGuid = getGamepadGuid(RBX::InputObject::TYPE_GAMEPAD1);
IVectorView<IGamepad^>^ gamepads = Windows::Xbox::Input::Gamepad::Gamepads;
for ( unsigned int i = 0; i < gamepads->Size; ++i )
{
IGamepad^ gamepad = gamepads->GetAt(i);
if (gamepad->Id == gamepadGuid)
{
gamepad->SetVibration(currentVibration);
break;
}
}
}
void XboxGameController::processControllerBuffer()
{
shared_ptr<RBX::DataModel> sharedDM = dataModel.lock();
if (!sharedDM)
{
return;
}
GamepadService* gamepadService = RBX::ServiceProvider::find<GamepadService>(sharedDM.get());
if (!gamepadService)
{
return;
}
UserInputService* inputService = RBX::ServiceProvider::find<UserInputService>(sharedDM.get());
if (!inputService)
{
return;
}
ControllerBuffer::GamepadValueBufferMap bufferMap = controllerBuffer->getBufferedInput();
for (ControllerBuffer::GamepadValueBufferMap::iterator iter = bufferMap.begin(); iter != bufferMap.end(); ++iter)
{
RBX::Gamepad gamepad = gamepadService->getGamepadState(GamepadService::getGamepadIntForEnum((*iter).first.first));
RBX::KeyCode keyCode = (*iter).first.second;
ControllerBuffer::GamepadValueStateHistoryVector historyVector = (*iter).second;
for (ControllerBuffer::GamepadValueStateHistoryVector::iterator historyIter = historyVector.begin(); historyIter != historyVector.end(); ++historyIter)
{
InputObject::UserInputState newState = (*historyIter).second;
Vector3 newValue = (*historyIter).first;
G3D::Vector3 lastPos = gamepad[keyCode]->getPosition();
if (lastPos != newValue)
{
gamepad[keyCode]->setPosition(newValue);
RBX::InputObject::UserInputState currentState = RBX::InputObject::INPUT_STATE_CHANGE;
if (newValue == G3D::Vector3::zero())
{
currentState = RBX::InputObject::INPUT_STATE_END;
}
else if (newValue.z >= 1.0f)
{
currentState = RBX::InputObject::INPUT_STATE_BEGIN;
}
gamepad[keyCode]->setDelta(newValue - lastPos);
gamepad[keyCode]->setInputState(currentState);
inputService->dangerousFireInputEvent(gamepad[keyCode], NULL);
}
}
}
updateVibration();
}
void XboxGameController::fireGamepadConnectedEvent(const int controllerIndex)
{
if (shared_ptr<RBX::DataModel> sharedDM = dataModel.lock())
{
if (RBX::UserInputService* inputService = RBX::ServiceProvider::find<RBX::UserInputService>(sharedDM.get()))
{
inputService->safeFireGamepadConnected(RBX::GamepadService::getGamepadEnumForInt(controllerIndex));
}
}
}
void XboxGameController::fireGamepadDisconnectedEvent(const int controllerIndex)
{
if (shared_ptr<RBX::DataModel> sharedDM = dataModel.lock())
{
if (RBX::UserInputService* inputService = RBX::ServiceProvider::find<RBX::UserInputService>(sharedDM.get()))
{
inputService->safeFireGamepadDisconnected(RBX::GamepadService::getGamepadEnumForInt(controllerIndex));
}
}
}
uint64 XboxGameController::getGamepadGuid(const InputObject::UserInputType rbxGamepadId)
{
return gamepadConnectedMap[RBX::GamepadService::getGamepadIntForEnum(rbxGamepadId)].guid;
}
void XboxGameController::findAvailableGamepadKeyCodesAndSet(RBX::InputObject::UserInputType gamepadType)
{
if (shared_ptr<RBX::DataModel> sharedDM = dataModel.lock())
{
if (RBX::UserInputService* inputService = RBX::ServiceProvider::find<RBX::UserInputService>(sharedDM.get()))
{
shared_ptr<RBX::Reflection::ValueArray> availableGamepadKeyCodes(new RBX::Reflection::ValueArray());
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONA);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONB);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONX);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONY);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONL1);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONR1);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONL2);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONR2);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONL3);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONR3);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_THUMBSTICK1);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_THUMBSTICK2);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_DPADUP);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_DPADDOWN);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_DPADLEFT);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_DPADRIGHT);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONSELECT);
availableGamepadKeyCodes->push_back(RBX::SDLK_GAMEPAD_BUTTONSTART);
inputService->setSupportedGamepadKeyCodes(gamepadType, availableGamepadKeyCodes);
}
}
}
void XboxGameController::setVibrationMotorsEnabled(RBX::InputObject::UserInputType gamepadType)
{
if (gamepadType != InputObject::TYPE_GAMEPAD1)
{
return;
}
if (shared_ptr<DataModel> dm = dataModel.lock())
{
if ( RBX::HapticService* hapticService = RBX::ServiceProvider::create<HapticService>(dm.get()) )
{
hapticService->setEnabledVibrationMotors(gamepadType, RBX::HapticService::MOTOR_LARGE, true);
hapticService->setEnabledVibrationMotors(gamepadType, RBX::HapticService::MOTOR_SMALL, true);
hapticService->setEnabledVibrationMotors(gamepadType, RBX::HapticService::MOTOR_LEFTTRIGGER, true);
hapticService->setEnabledVibrationMotors(gamepadType, RBX::HapticService::MOTOR_RIGHTTRIGGER, true);
}
}
}
void XboxGameController::setVibrationMotor(RBX::InputObject::UserInputType gamepadType, RBX::HapticService::VibrationMotor vibrationMotor, shared_ptr<const RBX::Reflection::Tuple> args)
{
if (!args)
{
return;
}
if (args->values.size() <= 0)
{
return;
}
if (gamepadType == InputObject::TYPE_GAMEPAD1)
{
float newMotorValue = 0.0f;
RBX::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
{
RBX::StandardOut::singleton()->printf(RBX::MESSAGE_ERROR, "First value to HapticService:SetMotor is not a valid number (must be a number between 0-1)");
return;
}
switch (vibrationMotor)
{
case RBX::HapticService::MOTOR_LARGE:
currentVibration.LeftMotorLevel = newMotorValue;
break;
case RBX::HapticService::MOTOR_SMALL:
currentVibration.RightMotorLevel = newMotorValue;
break;
case RBX::HapticService::MOTOR_LEFTTRIGGER:
currentVibration.LeftTriggerLevel = newMotorValue;
break;
case RBX::HapticService::MOTOR_RIGHTTRIGGER:
currentVibration.RightTriggerLevel = newMotorValue;
break;
default:
break;
}
}
}
+86
View File
@@ -0,0 +1,86 @@
#pragma once
#include <map>
#include "boost\weak_ptr.hpp"
#include "boost\shared_ptr.hpp"
#include "ControllerBuffer.h"
#include "util/KeyCode.h"
#include "Util/G3DCore.h"
#include "V8Tree/Service.h"
#include "v8datamodel/InputObject.h"
#include "v8datamodel/HapticService.h"
using namespace Windows::Xbox::Input;
using namespace Windows::Xbox::System;
namespace RBX
{
class DataModel;
class GamepadService;
class UserInputService;
}
class XboxGameController
{
friend class XboxGameController;
struct ControllerInfo {
bool isConnected;
uint64 guid;
};
private:
XboxGameController() {} //private because you should always be setting a dm when creating
boost::weak_ptr<RBX::DataModel> dataModel;
boost::shared_ptr<ControllerBuffer> controllerBuffer;
rbx::signals::scoped_connection getSupportedGamepadKeyCodesConnection;
rbx::signals::scoped_connection updateInputConnection;
rbx::signals::scoped_connection setEnabledVibrationMotorsConnection;
rbx::signals::scoped_connection setVibrationMotorConnection;
Windows::Foundation::EventRegistrationToken gamepadAddedEvent;
Windows::Foundation::EventRegistrationToken gamepadRemovedEvent;
std::map<int,ControllerInfo> gamepadConnectedMap;
std::map<std::pair<Platform::String^, unsigned long long>, RBX::InputObject::UserInputType> xboxLiveIdToRBXGamepadType;
bool initializedControllerGuidMap;
GamepadVibration currentVibration;
void fireGamepadConnectedEvent(const int controllerIndex);
void fireGamepadDisconnectedEvent(const int controllerIndex);
void handleNewGamepad(IGamepad^ gamepad);
void handleGamepadRemove(IGamepad^ gamepad);
void processControllerBuffer();
void updateVibration();
void findAvailableGamepadKeyCodesAndSet(RBX::InputObject::UserInputType gamepadType);
bool getRBXGamepadFromXboxLiveId(Platform::String^ xboxLiveId, unsigned long long controllerId, RBX::InputObject::UserInputType& gamepadEnum, int& gamepadInt);
void setVibrationMotorsEnabled(RBX::InputObject::UserInputType gamepadType);
public:
XboxGameController(boost::shared_ptr<RBX::DataModel> newDM, shared_ptr<ControllerBuffer> newControllerBuffer);
void setDataModel(boost::shared_ptr<RBX::DataModel> newDM);
void setupGamepadHandling();
void resetControllerGuidMap();
uint64 getGamepadGuid(const RBX::InputObject::UserInputType rbxGamepadId);
int getRbxGamepadIntFromGamepad(Windows::Xbox::Input::IGamepad^ gamepad);
void remapXboxLiveIdToRBXGamepadId(Platform::String^ xboxLiveId, unsigned long long controllerId, RBX::InputObject::UserInputType gamepadType);
void setVibrationMotor(RBX::InputObject::UserInputType gamepadType, RBX::HapticService::VibrationMotor vibrationMotor, shared_ptr<const RBX::Reflection::Tuple> args);
};
File diff suppressed because it is too large Load Diff
+94
View File
@@ -0,0 +1,94 @@
#include "v8datamodel/PlatformService.h"
#include <boost/unordered_set.hpp>
#include "VoiceChatBase.h"
using namespace Microsoft::Xbox::Services;
using namespace Microsoft::Xbox::Services::Multiplayer;
namespace RBX
{
class VoiceChatBase;
}
class XboxMultiplayerManager: public enable_shared_from_this <XboxMultiplayerManager>
{
public:
XboxMultiplayerManager(XboxLiveContext^ xblContext, GUID newPlayerSessionGUID,int newRobloxUserId = -1 );
~XboxMultiplayerManager();
void startMultiplayerListeners();
void stopMultiplayerListeners();
void joinMultiplayerSession(Platform::String^ handleID, Platform::String^ xuid);
void createGameSession(int pmpCreatorId = 0);
void joinGameSession(Platform::String^ gameSessionUri);
void leaveGameSession();
WriteSessionResult^ createPartySession();
void joinPartySession(Platform::String^ partySessionUri);
void leavePartySession();
MultiplayerSession^ createNewDefaultSession( Platform::String^ templateName, Platform::String^ sessionName, int pmpCreatorId = 0);
void sendGameInvite();
void setTeamChannel(unsigned char channelId);
void recentPlayersList();
void getInGamePlayers(shared_ptr<RBX::Reflection::ValueArray> values);
int requestJoinParty();
void updatePlayer(unsigned int rbxId, float distance, RBX::VoiceChatBase::TalkingDelta* talkingDeltaOut);
void muteVoiceChatPlayer(unsigned rbxId);
void unmuteVoiceChatPlayer(unsigned rbxId);
unsigned voiceChatGetState(int userId);
void xbEventMultiplayerRoundStart();
void xbEventMultiplayerRoundEnd();
int getLocalRobloxUserId() {return localRobloxUserId;}
int getPMPCreatorId();
static bool parseFromXboxCustomJson(Platform::String^ jsonStr,std::string str, int* out);
private:
XboxLiveContext^ xboxLiveContext;
MultiplayerSession^ gameSession;
MultiplayerSession^ partySession;
GUID playerSessionGuid;
RBX::Timer<RBX::Time::Precise> gametimer;
Windows::Foundation::EventRegistrationToken sessionChangeToken;
Windows::Foundation::EventRegistrationToken subscriptionLostToken;
int localRobloxUserId;
RBX::mutex stateLock;
RBX::mutex processLock;
RBX::mutex taskLock;
RBX::mutex voiceUsersLock;
bool expectedLeaveSession;
unsigned long long lastProcessedGameChange;
void onSessionChanged( Platform::Object^ object, RealTimeActivity::RealTimeActivityMultiplayerSessionChangeEventArgs^ arg );
void processSessionDeltas( MultiplayerSession^ currentSession, MultiplayerSession^ previousSession, unsigned long long lastChange );
void onSubscriptionLost( Platform::Object^ object, RealTimeActivity::RealTimeActivityMultiplayerSubscriptionsLostEventArgs^ arg );
//event MultiplayerStateChanged^ OnMultiplayerStateChanged;
void processSessionChange( MultiplayerSession^ session );
WriteSessionResult^ updateAndProcessSession( XboxLiveContext^ context, MultiplayerSession^ session, MultiplayerSessionWriteMode writeMode );
WriteSessionResult^ writeSession( XboxLiveContext^ context, MultiplayerSession^ session, MultiplayerSessionWriteMode writeMode );
inline bool isMultiplayerSessionChangeTypeSet( MultiplayerSessionChangeTypes value, MultiplayerSessionChangeTypes check )
{ return (value & check) == check; }
boost::shared_ptr<RBX::VoiceChatBase> voiceChat;
typedef boost::unordered_map<unsigned, unsigned> RbxIdToSessionIdMap;
RbxIdToSessionIdMap rbxIdToSessionId;
boost::unordered_set<unsigned> mutedUsersRbxIds; // Why is this here? It is to keep list of muted user while you play the game. We don't like it here too.
};
File diff suppressed because it is too large Load Diff
+218
View File
@@ -0,0 +1,218 @@
#pragma once
#include "V8Tree/Instance.h"
#include "V8Tree/Service.h"
#include "boost\weak_ptr.hpp"
#include "XbLiveUtils.h"
#include "XboxGameController.h"
#include "XboxMultiplayerManager.h"
#include "v8datamodel/InputObject.h"
#include "v8datamodel/PlatformService.h"
#include "v8datamodel/TeleportCallback.h"
using namespace Windows::Xbox::Input;
using namespace Windows::Xbox::System;
using namespace Windows::Networking::Connectivity;
using namespace Windows::Foundation::Collections;
using namespace Microsoft::Xbox::Services;
namespace RBX
{
class DataModel;
class DataModelJob;
class Verb;
class Game;
class ViewBase;
}
class Marshaller;
class RenderJob;
class ControllerBuffer;
class UserIDTranslator;
class KeyboardProvider;
class XboxPlatform: public RBX::IPlatformAPI, public RBX::TeleportCallback
{
public:
XboxPlatform();
virtual ~XboxPlatform(); // not that it matters...
void onProtocolActivated( Windows::ApplicationModel::Activation::IProtocolActivatedEventArgs^ args );
void onWindowActivatedChanged(Windows::UI::Core::WindowActivatedEventArgs^ args);
void tick(); // called by main
std::pair<unsigned, unsigned> getRenderSize() const;
void requestGameShutdown(bool teleport) override; // called by exit verb
void sendConsumeAllRequest(bool is_purchase);
void returnToEngagementScreen(RBX::ReturnToEngageScreenStatus status);
void attemptToSignActiveUserIn(std::string userToSignIn, IController^ controllerToUse);
void startEventHandlers();
void stopEventHandlers();
void suspendViewXbox();
void resumeViewXbox();
void onNormalResume();
void xbEventPlayerSessionStart();
void xbEventPlayerSessionEnd();
void xbEventPlayerSessionPause();
void xbEventPlayerSessionResume();
virtual void voiceChatSetMuteState(int userId, bool mute);
virtual unsigned voiceChatGetState(int userId);
User^ currentUser;
IController^ currentController;
Microsoft::Xbox::Services::XboxLiveContext^ xboxLiveContext;
private:
virtual RBX::AccountAuthResult performAuthorization(RBX::InputObject::UserInputType gamepadId, bool unLinkedCheck) override;
virtual RBX::GameStartResult startGame3( RBX::GameJoinType gt, int id );
virtual int netConnectionCheck() override;
virtual void setScreenResolution(double px, double py) override;
virtual int fetchFriends(RBX::InputObject::UserInputType gamepadId, std::string* result);
virtual int popupHelpUI();
virtual int launchPlatformUri(const std::string baseUri);
virtual void popupGameInviteUI();
virtual int popupPartyUI(RBX::InputObject::UserInputType gamepadId);
virtual int popupProfileUI(RBX::InputObject::UserInputType gamepadId, std::string xuid);
virtual int popupAccountPickerUI(RBX::InputObject::UserInputType gamepadId);
virtual int getPMPCreatorId();
virtual int getTitleId();
virtual shared_ptr<const RBX::Reflection::ValueTable> getVersionIdInfo();
virtual void showKeyBoard(std::string& title, std::string& description, std::string& defaultText, unsigned keyboardType, RBX::DataModel* dm);
virtual shared_ptr<const RBX::Reflection::ValueTable> getPlatformUserInfo() override;
// linking functions
virtual int performAccountLink(const std::string& accountName, const std::string& password, std::string* response) override;
virtual int performUnlinkAccount(std::string* response) override;
virtual int performSetRobloxCredentials(const std::string& accountName, const std::string& password, std::string* response) override;
virtual RBX::AccountAuthResult performHasRobloxCredentials() override;
virtual RBX::AccountAuthResult performHasLinkedAccount() override;
virtual int fetchInventoryInfo(shared_ptr<RBX::Reflection::ValueArray> values);
virtual int fetchCatalogInfo(shared_ptr<RBX::Reflection::ValueArray> values);
virtual RBX::PlatformPurchaseResult requestPurchase(const std::string& productId);
virtual int getPlatformPartyMembers(shared_ptr<RBX::Reflection::ValueArray> result);
virtual int getInGamePlayers(shared_ptr<RBX::Reflection::ValueArray> result);
virtual RBX::AwardResult awardAchievement(const std::string& eventName) override;
virtual RBX::AwardResult setHeroStat(const std::string& eventName, double* value) override;
// Teleport support
virtual void doTeleport(const std::string& url, const std::string& ticket, const std::string& script) override;
virtual bool isTeleportEnabled() const override;
virtual std::string xBox_getGamerTag() const override;
private:
bool activated; // whether or not the window is in focus
bool trySignInOnActivation; // set to true when user is logged out and needs to be relogged in
Marshaller* marshaller; // thread marshaller
RBX::Game* intro; // main menu
RBX::Game* game; // game being played (or null)
RBX::Game* current; // what the view is bound to, points to either *intro or *game
RBX::ViewBase* view; // renderer
RBX::Verb* exitVerb; // handles game exit from ESC menu
RBX::mutex gameMutex; // use this mutex if modifying game or exitVerb
volatile long gameShutdownGuard; // prevents shutdown requests from piling up
// makes sure we don't miss input during low FPS
shared_ptr<ControllerBuffer> controllerBuffer;
shared_ptr<RenderJob> renderJob;
shared_ptr<XboxGameController> controller;
shared_ptr<UserIDTranslator> userTranslator;
shared_ptr<RBX::DataModelJob> partyPoller;
shared_ptr<RBX::DataModelJob> validSessionPoller;
shared_ptr<RBX::DataModelJob> voiceChatPoller;
scoped_ptr<KeyboardProvider> keyboard;
shared_ptr<XboxMultiplayerManager> multiplayerManager;
struct PartyStatus
{
std::string currentPartyGuid;
std::string pollPartyGuid;
bool leaderInGame;
DWORD lastCheckTime;
bool tried;
PartyStatus(): lastCheckTime(0), leaderInGame(false), tried(false) {}
}
partyStatus;
struct GameInviteHandle{
std::string targetUserXuid;
int followUserId;
int pmpCreator; // used for Play My Place
GameInviteHandle(): followUserId(-1), targetUserXuid("") {}
}
gameInviteHandle;
void initVoiceChatPoller();
void removeVoiceChatPoller();
GUID playerSessionGuid;// used by xbox to track user session info
void setPartyPollStatus(const std::string& newGuid, bool leaderIn ); // can only be called on marshaller thread
void setPartyCreateStatus( const std::string& current ); // can only be called on marshaller thread
void setPartyTriedStatus();
void handlePartyJoin(); // can only be called on marshaller thread
void initPartyPoller();
void removePartyPoller();
RBX::GameStartResult prepareGameLaunch( std::string& authenticationUrl, std::string& authenticationTicket, std::string& scriptUrl, RBX::GameJoinType joinType, int id ); // fetches auth, ticket, script
RBX::GameStartResult initGame( const std::string& authUrl, const std::string& ticket, const std::string joinScriptUrl );
void switchView( RBX::Game* to ); // 0 to unbind from both
// these are called when we gain/lose focus of our window
void onActivated();
void onDeactivated();
volatile long returnToEngagementFlag;
volatile long consumeAllFlag;
RBX::mutex controllerPairingMutex;
void storeLocalGamerPicture(XboxLiveContext^ xboxLiveContext);
void checkValidSessionAsync(); // return to engagement screen if fails
void initValidSessionPoller();
void removeValidSessionPoller();
void initializeAuthEventHandlers();
void initializeNetworkConnectionEventHandlers();
void sampleInput();
void startControllerBuffering();
void endControllerBuffering();
User^ tryToSignInActiveUser(IController ^ controllerToUse);
void attemptToReconnectController(std::string userToSignIn);
User^ getActiveUser();
std::vector<IGamepad^> getGamepadsForCurrentUser();
void handleCurrentControllerChanged();
std::vector< Marketplace::CatalogItemDetails^ > catalogItemDetails;
bool setRichPresence();
void getCatalogInfo();
bool purchaseItem( const std::wstring& wstrSignedOffer );
void requestGameShutdown_nolock(bool teleport);
bool checkXboxPrivileges(unsigned privilegeID);
void setGameProgress();
void shutdownDataModels();
void fireGameJoinedEvent(RBX::GameStartResult); // wrapper for firing game joined event
RBX::AccountAuthResult xboxAuthHttpHelper( const std::string& url, std::string* response, bool isPost);
RBX::AccountAuthResult authAndInitUser();
};
+225
View File
@@ -0,0 +1,225 @@
#include "XboxUtils.h"
#include <fstream>
#include "v8xml/WebParser.h"
#include "RobloxServicesTools.h"
#include "v8datamodel/FastLogSettings.h"
#include "v8datamodel/DataModel.h"
#include "util/http.h"
#include "v8datamodel/DataModelJob.h"
#define XBOX_APP_SETTINGS_STRING "XboxAppSettings"
//////////////////////////////////////////////////////////////////////////
// fast flags
bool loadLocalFFlags()
{
std::string s;
std::copy( std::istream_iterator<char>( std::ifstream("fflags.json") ), std::istream_iterator<char>(), std::back_inserter(s) );
LoadClientSettingsFromString( CLIENT_APP_SETTINGS_STRING, s, &RBX::ClientAppSettings::singleton() );
return true;
}
static std::string getFFlagUrl( std::string baseUrl, std::string group, std::string apiKey)
{
auto pos = baseUrl.find_first_of("://www.");
if( pos == std::string::npos )
{
RBXASSERT( !"baseurl is missing ://www." ); // rewrite the function!
return "";
}
baseUrl.replace( pos, 7, "://clientsettings.api." );
return RBX::format( "%sSetting/QuietGet/%s/?apiKey=%s", baseUrl.c_str(), group.c_str(), apiKey.c_str() );
}
bool fetchFFlags(const char* baseUrl)
{
std::string fflagsClient;
std::string fflagsXbox;
std::string fflagClientUrl = getFFlagUrl(baseUrl, CLIENT_APP_SETTINGS_STRING, CLIENT_SETTINGS_API_KEY);
std::string fflagXboxUrl = getFFlagUrl(baseUrl, XBOX_APP_SETTINGS_STRING, CLIENT_SETTINGS_API_KEY);
enum { kSleepMs = 100, kTimeoutMs = 30000 };
try
{
RBX::HttpFuture result1 = RBX::HttpAsync::get(fflagClientUrl);
RBX::HttpFuture result2 = RBX::HttpAsync::get(fflagXboxUrl);
for( int j=0; ; j += kSleepMs )
{
if( j>kTimeoutMs )
{
dprintf("FFlag fetch timeout\n");
return false; // timeout
}
if( result1.get_state() == boost::future_state::ready &&
result2.get_state() == boost::future_state::ready )
{
fflagsClient = result1.get();
fflagsXbox = result2.get();
break;
}
::SleepEx(kSleepMs, TRUE);
}
if( fflagsClient.empty() || fflagsXbox.empty())
{
dprintf("FFlag fetch failed!\n");
return false;
}
LoadClientSettingsFromString( CLIENT_APP_SETTINGS_STRING, result1.get(), &RBX::ClientAppSettings::singleton() );
LoadClientSettingsFromString( XBOX_APP_SETTINGS_STRING, result2.get(), &RBX::ClientAppSettings::singleton() );
return true;
}
catch (const std::exception& e)
{
dprintf("FFlag fetch exception: %s\n", e.what());
}
return false;
}
//////////////////////////////////////////////////////////////////////////
// join script
static std::string readStringValue(shared_ptr<const RBX::Reflection::ValueTable> jsonResult, std::string name)
{
RBX::Reflection::ValueTable::const_iterator itData = jsonResult->find(name);
if (itData != jsonResult->end())
{
return itData->second.get<std::string>();
}
else
{
throw std::runtime_error(RBX::format("Unexpected string result for %s", name.c_str()));
}
}
static int readIntValue(shared_ptr<const RBX::Reflection::ValueTable> jsonResult, std::string name)
{
RBX::Reflection::ValueTable::const_iterator itData = jsonResult->find(name);
if (itData != jsonResult->end())
{
return itData->second.get<int>();
}
else
{
throw std::runtime_error(RBX::format("Unexpected int result for %s", name.c_str()));
}
}
PlaceLauncherResult requestPlaceInfo(const std::string url, std::string& authenticationUrl, std::string& ticket, std::string& scriptUrl)
{
try
{
std::string response;
RBX::Http(url).get(response);
std::stringstream jsonStream;
jsonStream << response;
shared_ptr<const RBX::Reflection::ValueTable> jsonResult(rbx::make_shared<const RBX::Reflection::ValueTable>());
bool parseResult = RBX::WebParser::parseJSONTable(jsonStream.str(), jsonResult);
if (!parseResult)
return PlaceLaunch_SomethingReallyBad;
int status = readIntValue(jsonResult, "status");
if (status != PlaceLaunch_Joining)
return (PlaceLauncherResult)status;
authenticationUrl = readStringValue(jsonResult, "authenticationUrl");
ticket = readStringValue(jsonResult, "authenticationTicket");
scriptUrl = readStringValue(jsonResult, "joinScriptUrl");
return PlaceLaunch_Joining;
}
catch (RBX::base_exception& e)
{
dprintf( "Exception when requesting place info: %s. ", e.what() );
}
return PlaceLaunch_SomethingReallyBad;
}
// Case-sensitive comparison of two Platform::String^ objects
bool isStringEqual(Platform::String^ val1,Platform::String^ val2)
{
return (wcscmp(val1->Data(), val2->Data() ) == 0);
}
// Case-insensitive comparison of two Platform::String^ objects
bool isStringEqualCaseInsensitive(Platform::String^ val1,Platform::String^ val2)
{
return (_wcsicmp(val1->Data(), val2->Data()) == 0);
}
std::string ws2s(const wchar_t* data)
{
// NOTE: had to hack it because std::codecvt is so BAD, it throws up if it encounters a unicode symbol
std::string result;
if(data)
{
for (const wchar_t* p = data; *p; ++p)
if ((unsigned)*p<128)
result.push_back(*p);
}
return result;
}
std::wstring s2ws(const std::string* data)
{
std::wstring ws(data->begin(), data->end());
return ws;
}
//////////////////////////////////////////////////////////////////////////
struct GenericDataModelJob : RBX::DataModelJob
{
double per;
std::function<void()> stepfn;
GenericDataModelJob( const char* name, int type, shared_ptr< RBX::DataModel> dm, double period, std::function<void()> step )
: RBX::DataModelJob(name, (TaskType)type, false, dm, RBX::Time::Interval(period) )
{
per = period;
stepfn = step;
}
virtual RBX::TaskScheduler::StepResult stepDataModelJob(const Stats& stats) override
{
if( stepfn ) stepfn();
return RBX::TaskScheduler::Stepped;
}
virtual RBX::Time::Interval sleepTime(const Stats& stats) override
{
return computeStandardSleepTime(stats, 1/per);
}
virtual RBX::TaskScheduler::Job::Error error(const Stats& stats) override
{
return computeStandardError(stats, 1/per);
}
};
shared_ptr<RBX::DataModelJob> addGenericDataModelJob( const char* name, int type, shared_ptr< RBX::DataModel> dm, double period, std::function<void()> step )
{
shared_ptr< RBX::DataModelJob > job ( new GenericDataModelJob(name, type, dm, period, step) );
RBX::TaskScheduler::singleton().add( job );
return job;
}
void removeGenericDataModelJob( shared_ptr< RBX::DataModelJob >& job, std::function<void()> spinfunc )
{
if( !job ) return;
RBX::TaskScheduler::singleton().removeBlocking(job, [=]()->void { spinfunc(); } );
job.reset();
}
+60
View File
@@ -0,0 +1,60 @@
#pragma once
// in this file...
// - fast flag fetching helpers
// - join script fetching/parsing helpers
// - unicode conversion
#include <string>
#include <locale>
#include <functional>
#include "rbx/Boost.hpp"
namespace RBX
{
class DataModel;
class DataModelJob;
}
void dprintf( const char* fmt, ... );
bool loadLocalFFlags();
bool fetchFFlags(const char* baseUrl);
// status codes
enum PlaceLauncherResult
{
PlaceLaunch_Waiting = 0, // wait
PlaceLaunch_Loading = 1, // wait
PlaceLaunch_Joining = 2, // *the* success code!
PlaceLaunch_Disabled = 3,
PlaceLaunch_Error = 4,
PlaceLaunch_GameEnded = 5,
PlaceLaunch_GameFull = 6,
PlaceLaunch_UserLeft = 10,
PlaceLaunch_Restricted = 11,
PlaceLaunch_Unauthorized = 12,
PlaceLaunch_SomethingReallyBad = 1000, // not a real status
};
PlaceLauncherResult requestPlaceInfo(const std::string url, std::string& authenticationUrl, std::string& ticket, std::string& scriptUrl);
bool isStringEqual(Platform::String^ val1,Platform::String^ val2);
bool isStringEqualCaseInsensitive(Platform::String^ val1,Platform::String^ val2);
std::string ws2s(const wchar_t* data);
std::wstring s2ws(const std::string* data);
template< class M >
inline typename M::mapped_type* mapget( M& m, const typename M::key_type& k )
{
M::iterator it = m.find(k);
if( it == m.end() ) return 0;
return &it->second;
}
shared_ptr< RBX::DataModelJob > addGenericDataModelJob( const char* name, int type, shared_ptr< RBX::DataModel> dm, double period, std::function<void()> step );
void removeGenericDataModelJob( shared_ptr< RBX::DataModelJob >& job, std::function<void()> spinfunc );
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
#include "async.h"
namespace AsyncDetail
{
extern int g_asyncLeaked = 0;
}
+222
View File
@@ -0,0 +1,222 @@
#pragma once
//
// Many xbox functions return an IAsyncOperation<T> and leave you to deal with it.
// This dirty little helper can take away some of the pain.
//
// Example: suppose you want to call this monstrosity: IAsyncOperation<ISomeResult^>^ SomeXboxClass::SomeAsyncMethod();
//
// Use case #1: get/subscribe/wait
//
// async( var->SomeXBoxMethod() ).complete( // - install the 'completed' event handler
// [<captures>]( ISomeResult^ result )
// {
// <your-completed-handler-goes-here>;
// }
// ).except( [<captures>]( Platform::Exception^ e ) // - install the exception handler.
// { // if you don't do that, join() will rethrow the exception on the calling thread
// <your-exception-handler-goes-here>;
// }
// ).join(); // - wait until it finishes
//
// Use case #2: several parallel operations:
//
// auto& a1 = async( var->SomeXBoxMethod() ).complete( <same handler> ).except( .... ); // do not call join yet
// auto& a2 = async( var2->SomeOtherMethod() ).complete( <handler> ).except( .... ); // neither yet
// <do stuff>;
// a1.join(); a2.join();
//
// Use case #3: don't care to wait
// async( var->SomeXBoxMethod() ).complete( <same handler> ).except( .... ).detach(); // will return immediately without waiting
//
// You MUST call either .join() or .detach() on *every* async instance you spawn, otherwise this will leak the instances.
// g_asyncLeaked contains the number of async instances still alive.
//
#include <wrl.h>
#include <functional>
#include <atomic>
namespace AsyncDetail
{
extern int g_asyncLeaked;
using Windows::Foundation::IAsyncAction;
using Windows::Foundation::IAsyncOperation;
using Windows::Foundation::AsyncStatus;
// abstracts different Async Types,
template< class Op > struct subscriber; // not implemented
template< class Ty > struct subscriber< IAsyncOperation<Ty> >
{
typedef Ty result_type;
typedef IAsyncOperation<Ty> op_type;
static void subscribe( op_type^ op, std::function< void(op_type^, AsyncStatus) > fn )
{
op->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<result_type>( fn );
}
template< class Fn >
static void call_handler( op_type^ op, Fn& fn ) { fn( op->GetResults() ); }
};
template<> struct subscriber<IAsyncAction>
{
typedef IAsyncAction op_type;
static void subscribe( op_type^ op, std::function< void(op_type^, AsyncStatus) > fn )
{
op->Completed = ref new Windows::Foundation::AsyncActionCompletedHandler( fn );
}
template< class Fn >
static void call_handler( op_type^ op, Fn& fn ) { op->GetResults(); fn(); }
};
template< class Ty, class Op >
class async_caller
{
typedef async_caller<Ty, Op> myt;
typedef std::function<void(Ty)> func_success;
typedef std::function<void()> func_error;
typedef Op opera;
typedef Windows::Foundation::IAsyncAction action;
typedef Platform::Exception exception;
typedef std::function<void(exception^ e)> excfunc;
func_success m_fn_success;
func_error m_fn_error;
func_error m_fn_cancelled;
opera^ m_op;
exception ^m_xcpt;
excfunc m_excfn;
std::atomic<int> m_done;
public:
static myt& create( opera^ op ) { return *new myt(op); }
myt& complete( func_success fn )
{
m_fn_success = fn;
return *this;
}
myt& error( func_error fn )
{
m_fn_error = fn;
return * this;
}
myt& cancelled( func_error fn )
{
m_fn_cancelled = fn;
return *this;
}
myt& except(excfunc fn)
{
m_excfn = fn;
return *this;
}
void join()
{
install_handlers();
while ( m_op->Status == Windows::Foundation::AsyncStatus::Started || !m_done.load() )
{
::Sleep(1);
}
if( m_xcpt )
{
if( m_excfn )
m_excfn(m_xcpt);
else
{
delete this;
throw m_xcpt; // exception translation: if there was an exception on the async thread, this will make sure the exception propagates to the calling thread.
}
}
delete this;
}
void detach()
{
install_handlers();
if( m_excfn ) // nope!
RBXASSERT( !"Do not install exception handlers if you're calling detach(). There is no meaningful exception translation possible in this case." );
int expect = 0;
if( !m_done.compare_exchange_strong( expect, 1 ) ) // are we done yet?
{
delete this; // kill self, otherwise the handler will do that from its own context
}
}
private:
async_caller( opera^ op ): m_op(op), m_done(0) { g_asyncLeaked++; }
~async_caller() { g_asyncLeaked--; }
async_caller(); // = delete; // use auto& a instead.
async_caller( const myt& ); // = delete;
void operator=(const myt&); // = delete;
void install_handlers()
{
subscriber<Op>::subscribe( m_op,
[this](opera^ operation, AsyncStatus status) -> void
{
try
{
switch (status)
{
case Windows::Foundation::AsyncStatus::Canceled:
if( m_fn_cancelled )
m_fn_cancelled();
break;
case Windows::Foundation::AsyncStatus::Completed:
if( m_fn_success )
subscriber<Op>::call_handler( m_op, m_fn_success );
break;
case Windows::Foundation::AsyncStatus::Error:
if( m_fn_error )
m_fn_error();
break;
default:
RBXASSERT(!"should not happen");
break;
}
}
catch( exception^ e )
{
m_xcpt = e;
}
int expect = 0;
if( !m_done.compare_exchange_strong( expect, 1 ) )
{
delete this; // detach() has been already called, delete self and exit
}
}
);
}
};
} // ns AsyncDetail
template <class Ty>
inline AsyncDetail::async_caller<Ty, Windows::Foundation::IAsyncOperation<Ty> >& async( Windows::Foundation::IAsyncOperation<Ty>^ op )
{
return AsyncDetail::async_caller<Ty, Windows::Foundation::IAsyncOperation<Ty> >::create(op);
}
inline AsyncDetail::async_caller<void, Windows::Foundation::IAsyncAction>& async( Windows::Foundation::IAsyncAction^ op )
{
return AsyncDetail::async_caller<void, Windows::Foundation::IAsyncAction>::create(op);
}
+1
View File
@@ -0,0 +1 @@
1
+31
View File
@@ -0,0 +1,31 @@
'''
This small tool fetches fastflags from prod and prints to standard output.
Usage:
python fetchfflags.py
'''
import sys;
import urllib;
test = "http://clientsettings.api.watrbx.wtf/Setting/QuietGet/ClientAppSettings/?apiKey=76E5A40C-3AE1-4028-9F10-7C62520BD94F"
BASE_SITE = "watrbx.wtf"
#BASE_SITE = "gametest5.pizzaboxer.fun"
API_KEY = "76E5A40C-3AE1-4028-9F10-7C62520BD94F"
def main():
sys.stderr.write("Fetching fast flags...\n")
url = "http://clientsettings.api.%s/Setting/QuietGet/ClientAppSettings/?apiKey=%s" % (BASE_SITE, API_KEY)
result = urllib.urlopen(url)
if result.getcode() != 200:
sys.exit(1)
try:
for line in result:
print line,
finally:
result.close()
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+276
View File
@@ -0,0 +1,276 @@
#include <xdk.h>
#include <mmdeviceapi.h>
#include <wrl.h>
#include <ppltasks.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <io.h>
#include "XboxService.h"
#include "XboxUtils.h"
#include "async.h"
#include "v8datamodel/GameSettings.h"
#include "V8DataModel/GameBasicSettings.h"
using namespace Windows::Foundation;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::UI::Core;
using namespace Concurrency;
extern void dprintf( const char* fmt, ... );
FASTFLAGVARIABLE(ForceRetail, true);
ref class ViewProvider sealed : public Windows::ApplicationModel::Core::IFrameworkView
{
public:
ViewProvider();
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView );
virtual void SetWindow(Windows::UI::Core::CoreWindow^ wnd);
virtual void Load( _In_ Platform::String^ entryPoint );
virtual void Run();
virtual void Uninitialize();
protected:
// Event Handlers
void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
void OnResourceAvailabilityChanged(Platform::Object^ sender, Platform::Object^ args);
void OnExiting(Platform::Object^ sender, Platform::Object^ args);
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
void OnResuming(Platform::Object^ sender, Platform::Object^ args);
void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
private:
XboxPlatform* plt;
};
ref class ViewProviderFactory sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
{
public:
ViewProviderFactory() {}
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView() { return ref new ViewProvider; }
};
//////////////////////////////////////////////////////////////////////////
/////////////////////////////
ViewProvider::ViewProvider()
{
}
void ViewProvider::Initialize(CoreApplicationView^ applicationView)
{
applicationView->Activated += ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &ViewProvider::OnActivated);
CoreApplication::ResourceAvailabilityChanged += ref new EventHandler<Platform::Object^>(this, &ViewProvider::OnResourceAvailabilityChanged);
CoreApplication::Exiting += ref new EventHandler<Platform::Object^>(this, &ViewProvider::OnExiting);
CoreApplication::Suspending += ref new EventHandler<SuspendingEventArgs^>(this, &ViewProvider::OnSuspending);
CoreApplication::Resuming += ref new EventHandler<Platform::Object^>(this, &ViewProvider::OnResuming);
}
void ViewProvider::SetWindow(Windows::UI::Core::CoreWindow^ wnd)
{
plt = new XboxPlatform();
}
void ViewProvider::Run()
{
RBX::StandardOut::singleton()->messageOut.connect( [](const RBX::StandardOutMessage& m) -> void { dprintf( "%s\n", m.message.c_str() ); } );
while (true)
{
Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents( Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent );
plt->tick();
}
}
// The purpose of this method is to get the application entry point.
void ViewProvider::Load(Platform::String^ entryPoint)
{
}
void ViewProvider::Uninitialize()
{
delete plt;
}
// Called when the application is activated.
void ViewProvider::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
if (args->Kind == Windows::ApplicationModel::Activation::ActivationKind::Protocol)
{
// Tell the game object we had a protocol activation so it can setup state appropriately.
plt->onProtocolActivated(
static_cast<IProtocolActivatedEventArgs^>(args)
);
}
//CoreWindow::GetForCurrentThread()->Activate();
}
void ViewProvider::OnExiting(Platform::Object^ sender, Platform::Object^ args)
{
RBX::GlobalBasicSettings::singleton()->saveState();
RBX::GlobalAdvancedSettings::singleton()->saveState();
}
void ViewProvider::OnResourceAvailabilityChanged(Platform::Object^ sender, Platform::Object^ args)
{
// check to see if going into constrained or leaving constrained
if(CoreApplication::ResourceAvailability == Windows::ApplicationModel::Core::ResourceAvailability::Constrained)
{
dprintf("entering constrained state\n");
plt->xbEventPlayerSessionPause();
plt->stopEventHandlers();
}
else
{
dprintf("leaving constrained state\n");
if(!plt->xboxLiveContext) return;
plt->startEventHandlers();
plt->xbEventPlayerSessionResume();
// leaving constrained state for running
// check for inventory
async(plt->xboxLiveContext->InventoryService->GetInventoryItemsAsync( Microsoft::Xbox::Services::Marketplace::MediaItemType::GameConsumable )).complete(
[this](Marketplace::InventoryItemsResult^ inventoryResult){
try
{
// Because we may be compiling a list of multiple content types from separate
// calls, we just append the results to the passed in vector.
if(inventoryResult->Items->Size > 0)
{
for(int i = 0; i < inventoryResult->Items->Size;i++)
{
if(inventoryResult->Items->GetAt(i)->ConsumableBalance > 0)
{
plt->sendConsumeAllRequest(true);
break;
}
}
}
}
catch (Platform::Exception^ ex)
{
}
}).join();
}
}
// Called when the application is suspending.
void ViewProvider::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
dprintf("Suspending...\n");
try
{
plt->xbEventPlayerSessionEnd();
// this needs to be the last thing we do on suspend
plt->suspendViewXbox();
}
catch(Platform::Exception ^ex)
{
dprintf("Suspending view failed 0x%x\n", ex->HResult);
}
}
// Called when the application is resuming from suspended.
void ViewProvider::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
try
{
// this needs to be the first thing we do on resume
plt->resumeViewXbox();
// Note: that resume changes the suspend state to constrained state
// then changes the constrained state to running state
dprintf("Resuming...\n");
if( plt->currentUser && plt->xboxLiveContext && plt->currentUser->XboxUserId)
{
//current user is signed in
auto users = Windows::Xbox::System::User::Users;
for(int i = 0; i < users->Size; i++)
{
if(users->GetAt(i) == plt->currentUser)
{
if(users->GetAt(i)->IsSignedIn)
{
if( isStringEqual(users->GetAt(i)->XboxUserId, Windows::Xbox::ApplicationModel::Core::CoreApplicationContext::CurrentUser->XboxUserId))
{
dprintf("resuming for returning player\n");
//checking if user's controller has changed
for(auto controller : Windows::Xbox::ApplicationModel::Core::CoreApplicationContext::CurrentUser->Controllers)
{
if (controller == plt->currentController)
{
// normal resume
plt->xbEventPlayerSessionStart();
plt->onNormalResume();
return;
}
}
}
plt->returnToEngagementScreen(RBX::ReturnToEngage_ControllerChange);
return;
}
break;
}
}
// if the current user is no longer signed in, what then?
dprintf("resuming for absense of player\n");
plt->returnToEngagementScreen(RBX::ReturnToEngage_SignOut);
}
}
catch(Platform::Exception ^ex)
{
dprintf("Resuming view failed 0x%x\n", ex->HResult);
}
}
[Platform::MTAThread]
int main(Platform::Array< Platform::String^ >^)
{
// !!! Do not remove the following line, this makes sure mmdevapi.dll is linked
SetWasapiThreadAffinityMask(SetWasapiThreadAffinityMask(1));
Windows::ApplicationModel::Core::CoreApplication::Run( ref new ViewProviderFactory() );
}
extern int isRetail()
{
#ifdef _NOOPT
return 0;
#else
// let's hope the docs and the xbox dev forums are correct on this one
// that the d:\ partition is "not available" on retail consoles
static int x = 0 != _access("d:\\", 0);
return x || FFlag::ForceRetail; // fflag is just in case if the d:\ drive is not enough, but the flag won't come in until the intro is initialized, so there might be some debug output happening
#endif
}
extern void dprintf( const char* fmt, ... )
{
if( isRetail() ) return;
va_list va;
va_start( va, fmt );
char buffer[4096];
vsnprintf( buffer, sizeof(buffer), fmt, va );
va_end(va);
OutputDebugStringA(buffer);
}
+146
View File
@@ -0,0 +1,146 @@
#include "marshaller.h"
#include <xdk.h>
#include <windows.h>
#include <synchapi.h>
#include "rbx/Debug.h"
#include "rbx/Profiler.h"
__declspec(thread) static void* g_syncEvent; // per thread
extern void dprintf( const char* fmt, ... );
void* Marshaller::getSyncEvent()
{
if( !g_syncEvent )
{
g_syncEvent = CreateEvent(0, 0, 0, 0);
RBX::mutex::scoped_lock lck(cleanupMutex);
cleanup.push_back(&g_syncEvent);
}
return g_syncEvent;
}
Marshaller::Marshaller()
{
mainThread = GetCurrentThreadId();
hmainThread = OpenThread(THREAD_ALL_ACCESS, FALSE, mainThread);
RBXASSERT(hmainThread);
dprintf( "Marshaller started on thread %I64x (%I64d)\n", mainThread, mainThread );
}
Marshaller::~Marshaller()
{
CloseHandle(hmainThread);
for( int j=0, e=(int)cleanup.size(); j<e; ++j )
{
CloseHandle(*cleanup[j]);
*cleanup[j] = 0;
}
}
void Marshaller::submit(Func job)
{
JobDesc desc = JobDesc();
desc.job = job;
desc.result = 0;
RBX::mutex::scoped_lock lock (jqMutex);
jobQueue.push_back(desc);
}
void Marshaller::execute(Func job)
{
if( GetCurrentThreadId() == mainThread )
{
job();
return;
}
void* syncEvent = getSyncEvent();
ResetEvent(syncEvent); // just in case
JobResult result = {};
result.sync = syncEvent;
JobDesc desc = JobDesc();
desc.job = job;
desc.result = &result;
if(1)
{
RBX::mutex::scoped_lock lock (jqMutex);
jobQueue.push_back(desc);
}
WaitForSingleObject( syncEvent, INFINITE ); // wait for the result
if (!result.success)
{
throw RBX::runtime_error( "Marshaller cross-thread exception: '%s'", result.except.c_str() );
}
}
void Marshaller::waitEvents()
{
RBXPROFILER_SCOPE("xbox", __FUNCTION__);/*
for( int j=0; j<20; ++j )
{
if( runJob() ) break;
SleepEx(100, TRUE);
}
*/
}
void Marshaller::processEvents()
{
RBXPROFILER_SCOPE("xbox", __FUNCTION__);
while( runJob() ) {}
}
bool Marshaller::runJob()
{
JobDesc desc;
if(1)
{
RBX::mutex::scoped_lock lock (jqMutex);
if(jobQueue.empty()) return false;
desc = jobQueue.front();
jobQueue.erase( jobQueue.begin() );
}
try
{
desc.job();
if (desc.result)
desc.result->success = true;
}
catch (const std::exception& e)
{
if (desc.result)
{
desc.result->success = false;
desc.result->except = e.what();
}
else
{
// We've got nothing to report to, just dump it somewhere
// TODO: replace with debugging stuff
dprintf("%s\n", e.what());
RBXASSERT(0); // haha, exceptions suck
}
}
if (desc.result && desc.result->sync)
{
SetEvent(desc.result->sync);
}
return true;
}
+60
View File
@@ -0,0 +1,60 @@
#pragma once
#include <boost/weak_ptr.hpp>
#include <boost/function.hpp>
#include <vector>
#include "rbx/threadsafe.h"
class Marshaller
{
typedef boost::function<void()> Func;
public:
Marshaller();
~Marshaller();
// Executes the given function.
void execute(Func job);
// Submits a function to be executed by a separate thread.
void submit(Func job);
// blocks until something interesting happens
void waitEvents();
// processes all pending callbacks
void processEvents();
// returns marshaller thread
DWORD getThreadId() const { return mainThread; }
private:
struct JobResult
{
bool success;
std::string except;
void* sync;
};
struct JobDesc
{
Func job;
JobResult* volatile result;
};
unsigned mainThread; // not the 'main' main thread
void* hmainThread; // handle to the main thread
RBX::mutex jqMutex;
std::vector< JobDesc > jobQueue;
RBX::mutex cleanupMutex;
std::vector< void** > cleanup;
void* getSyncEvent();
bool runJob();
};
extern void main_processWinRTEvents(); // used to call into WinRT crap, defined in main.cpp
+600
View File
@@ -0,0 +1,600 @@
#include "p2p.h"
#include <collection.h>
#include "rbx/Debug.h"
#include "async.h"
extern void dprintf( const char* fmt, ... );
enum { dbg = 0 };
//#undef RBXASSERT
//#define RBXASSERT(X) ( (void)( (X) || (__debugbreak(), 1) ) )
namespace Xp2p
{
const wchar_t* kChatTemplateName = L"MultiplayerUdp"; // check appmanifest
enum
{
kRetransmitMaxPackets = 3,
kRetransmitPeriodMs = 1000,
kRetransmitLoopMs = 30,
kRetransmitQueueLength = 1000,
};
//////////////////////////////////////////////////////////////////////////
Address::Address()
{
memset( &rawdata, 0, sizeof(rawdata) );
}
Address::Address(in6_addr addr, unsigned port)
{
memset( &rawdata, 0, sizeof(rawdata) );
sockaddr_in6& sa = (sockaddr_in6&)rawdata;
sa.sin6_family = AF_INET6;
sa.sin6_port = htons(port);
sa.sin6_addr = addr;
}
char* Address::str(char* to ) const
{
char buf[128];
inet_ntop(AF_INET6, &addr6(), buf, 128 );
sprintf( to, "%s:%u", buf, port() );
return to;
}
//////////////////////////////////////////////////////////////////////////
Sock::Sock(unsigned port)
{
int result;
fd = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP );
int v6only = 0;
setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&v6only, sizeof(v6only) ); // MS tells to do this, idk.
Address local( in6addr_any, port );
result = bind( fd, local.toSockaddr(), local.size() );
if(dbg) dprintf( "p2p: socket %d bind to local %d\n", fd, result );
}
Sock::~Sock()
{
closesocket( fd );
if(dbg) dprintf( "p2p: socket %d closed\n", fd );
}
int Sock::send( const Address& to, const void* data, unsigned size, unsigned timeoutMs )
{
RBXASSERT(data);
fd_set set;
int result;
timeval tout = { timeoutMs / 1000, (timeoutMs % 1000)*1000 };
FD_ZERO( &set );
FD_SET( fd, &set );
result = select( 1, 0, &set, 0, &tout );
if( result > 0 && FD_ISSET( fd, &set ) )
{
result = ::sendto( fd, (const char*)data, size, 0, to.toSockaddr(), to.size() );
DWORD err = WSAGetLastError();
return result;
}
if( result == 0 )
{
return Net_Timeout;
}
return Net_Fail;
}
int Sock::recv( Address* from, void* data, unsigned size, unsigned timeoutMs )
{
RBXASSERT(from);
RBXASSERT(data);
fd_set set;
int result;
int namelen = from->size();
timeval tout = { timeoutMs / 1000, (timeoutMs % 1000)*1000 };
FD_ZERO( &set );
FD_SET( fd, &set );
result = select( 1, &set, 0, 0, &tout );
if( result > 0 && FD_ISSET( fd, &set ) )
{
result = ::recvfrom( fd, (char*)data, size, 0, from->toSockaddr(), &namelen );
DWORD err = WSAGetLastError();
return result;
}
if( result == 0 )
{
return Net_Timeout;
}
return Net_Fail;
}
//////////////////////////////////////////////////////////////////////////
//
Peer::Peer()
{
state = State_New;
pingTime = 0;
userData = 0;
devAssoc = nullptr;
userObject = nullptr;
txseq = 0;
rxseq = 0;
txseqR = 0;
rxseqR = 0;
rxackR = 0;
id = 0xffffffff;
}
int Peer::setstate( int expect, int replace )
{
return InterlockedCompareExchange( &state, replace, expect );
}
//////////////////////////////////////////////////////////////////////////
static void dbgPrintPacket( const PacketHeader* header )
{
dprintf( "packet: id %u type %u size %u peer %u seq %u seqR %u flags 0x%x\n", (unsigned)header->id, (unsigned)header->type, (unsigned)header->size, (unsigned)header->id, (unsigned)header->seq, (unsigned)header->seqR, (unsigned)header->flags );
}
static void dbgPrintTx( PeerPtr peer )
{
dprintf( "peer: id %u tx %u rx %u txr %u rxr %u\n", (unsigned)peer->id, (unsigned)peer->txseq, (unsigned)peer->rxseq, (unsigned)peer->txseqR, (unsigned)peer->rxseqR );
}
//////////////////////////////////////////////////////////////////////////
Network::Network( MultiplayerSessionMember^ currentUser )
: sock( kNetworkPort )
{
myMemberId = currentUser->MemberId;
assTemplate = SecureDeviceAssociationTemplate::GetTemplateByName( ref new Platform::String(kChatTemplateName) );
controlRunFlag = 1;
controlThreadObject = boost::thread( [this]()->void { controlThread(); } );
incomingHandler = assTemplate->AssociationIncoming += ref new TypedEventHandler<SecureDeviceAssociationTemplate^, SecureDeviceAssociationIncomingEventArgs^>(
[this]( SecureDeviceAssociationTemplate^, SecureDeviceAssociationIncomingEventArgs^ args )->void
{
lock lck(peerMutex);
pendingList.push_back( args->Association );
if(dbg) dprintf( "p2p: incoming association: %S\n", args->Association->RemoteHostName->DisplayName->Data() );
}
);
}
Network::~Network()
{
controlRunFlag = 0;
controlThreadObject.join();
{
lock lck(peerMutex);
for( auto p: peers )
destroyPeer(p);
}
for( unsigned num = 1; num; )
{
{
lock lck(peerMutex);
num = peers.size();
}
Sleep(10);
}
assTemplate->AssociationIncoming -= incomingHandler;
}
NetResult Network::sendPacket( PeerPtr peer, PacketHeader* packet, unsigned timeoutMs, unsigned flags )
{
RBXASSERT( packet->type != 0 ); // don't use type 0, probably an error!
RBXASSERT( packet->size <= sizeof(PacketStorage) ); // uwot!
RBXASSERT( packet->size >= sizeof(PacketHeader) ); // uwot! #2
RBXASSERT( peer.get() );
int oldstate = peer->setstate( Peer::State_Ready, Peer::State_Busy );
switch(oldstate)
{
case Peer::State_Ready:
break;
case Peer::State_Busy:
case Peer::State_Busy2:
return Net_Retry;
default:
return Net_NotReady;
}
packet->id = myMemberId;
packet->flags = flags;
packet->seq = ++ peer->txseq;
packet->timestamp = GetTickCount();
if( flags & Packet_Reliable )
{
packet->seqR = ++ peer->txseqR;
if( peer->reliable.size() < kRetransmitQueueLength )
{
PacketHeader* copy = (PacketHeader*)malloc( packet->size ); // retain the packet
memcpy( copy, packet, packet->size );
peer->reliable.push_back( copy );
}
else
{
dprintf( "p2p: WARN: peer retransmit queue is FULL, packet will not be reliable: ");
dbgPrintPacket(packet);
}
}
else
{
packet->seqR = peer->txseqR;
}
// NOTE: do not change the packet below! If it's reliable, its copy will not have the changes!
if( Peer::State_Busy != peer->setstate( Peer::State_Busy, Peer::State_Ready ) )
RBXASSERT( !"peer lock violation" );
char buf[128];
if(dbg) dprintf( "p2p: outgoing to %s (%u) type %u seq %u seqR %u size %u flags 0x%x", peer->remoteAddr.str(buf), (unsigned)packet->id, (unsigned)packet->type, (unsigned)packet->seq, (unsigned)packet->seqR, (unsigned)packet->size, (unsigned)packet->flags );
// assumes peer->remoteAddr never changes
int result = sock.send( peer->remoteAddr, packet, packet->size, timeoutMs );
if(dbg) dprintf( result == packet->size? "... ok\n": "... failed!\n" );
if( result < 0 )
{
return (NetResult)result;
}
if( result != packet->size )
{
return Net_Fail;
}
return Net_Ok;
}
NetResult Network::recvPacket( PacketStorage* packet, unsigned timeoutMs )
{
Address from;
int result = sock.recv( &from, packet, sizeof(PacketStorage), timeoutMs );
if( result < 0 ) return (NetResult)result; // recv error (timeout/disconnect/whatever)
if( packet->size > sizeof(PacketStorage) ) return Net_Packet; // bad packet size
if( (unsigned)result < sizeof(PacketHeader) ) return Net_Packet; // bad packet size
char buf[128];
if(dbg) dprintf("p2p: incoming from %s (%u) type %u seq %u seqR %u size %u flags 0x%x ... ok\n", from.str(buf), (unsigned)packet->id, (unsigned)packet->type, (unsigned)packet->seq, (unsigned)packet->seqR, (unsigned)packet->size, (unsigned)packet->flags );
return Net_Ok;
}
// it's kinda out-of-band, sequencing is irrelevant
static bool sendAck( Sock& sock, const Address& addr, unsigned myid, unsigned seqR )
{
PacketHeader ack = {};
ack.type = 0; // yep
ack.seqR = seqR;
ack.id = myid;
ack.timestamp = GetTickCount();
int acqr = sock.send( addr, &ack, sizeof(ack), 10 );
return acqr == sizeof(ack);
}
NetResult Network::processPacket( PeerPtr& who, PacketHeader* header )
{
char buf[120];
if(1)
{
lock lck(peerMutex);
for( auto& itor: peers ) if( itor->id == header->id ) { who = itor; break; }
}
if( !who ) return Net_Peer;
int oldstate = who->setstate( Peer::State_Ready, Peer::State_Busy );
switch(oldstate)
{
case Peer::State_Ready:
break;
case Peer::State_Busy:
case Peer::State_Busy2:
return Net_Retry;
default:
return Net_NotReady;
}
Address remoteAddr( who->remoteAddr );
bool isReliable = header->flags & Packet_Reliable;
bool needAck = false;
NetResult result; // intentionally uninitialized
if( header->type == 0 ) // it's an ack packet from the peer
{
if( header->seqR == who->rxackR + 1 )
{
if(dbg) dprintf("p2p: got ACK for %u\n", header->seqR );
who->rxackR = header->seqR;
}
result = Net_Packet; // the client is not interested in it, discard
}
else if( isReliable )
{
if( header->seqR == who->rxseqR + 1 ) // okay: although the reliable packet is what we expect, looks like we're going to lose some unreliable packets later
{
needAck = true;
result = Net_Ok;
}
else if( header->seqR <= who->rxseqR ) // okay..ish: it's from the past, so we discard the packet but send an ack
{
needAck = true;
result = Net_Packet;
}
else // it's from the future, so discard, because there's another reliable packet in flight
{
result = Net_Packet;
}
}
else // regular
{
if( header->seq >= who->rxseq + 1 ) // packet is in-sequence or from the future
{
if( header->seqR == who->rxseqR ) // good: we don't have any reliable packets in-between, so even if the packet is from the future, we still accept it
{
result = Net_Ok;
}
else // bad: there's a reliable packet with a lower 'seq' that's not been delivered yet, discard this packet
{
result = Net_Packet;
}
}
else // the packet is from the past, discard
{
result = Net_Packet;
}
}
// final step:
if( result == Net_Ok ) // update on success
{
who->rxseq = header->seq;
who->rxseqR = header->seqR;
who->pingTime = GetTickCount();
}
who->setstate( Peer::State_Busy, Peer::State_Ready );
if( needAck )
{
sendAck(sock, remoteAddr, myMemberId, header->seqR);
}
return result;
}
PeerPtr Network::createPeer( MultiplayerSessionMember^ member, boost::function<void(PeerPtr)> onConnected )
{
lock lck(peerMutex);
for( auto x: peers )
if( x->id == member->MemberId )
return x;
PeerPtr peer( new Peer );
peers.push_back(peer);
boost::thread( [this, peer, member, onConnected]() -> void { connectPeer( peer, member, onConnected ); } ).detach();
return peer;
}
void Network::destroyPeer( PeerPtr peer )
{
RBXASSERT( !peers.empty() ); // um...
boost::thread(
[this, peer]() -> void
{
unsigned index;
for (;;)
{
peerMutex.lock();
index = std::find( peers.begin(), peers.end(), peer ) - peers.begin();
if( index == peers.size() ) { peerMutex.unlock(); return; } // not found
if( Peer::State_Ready == peer->setstate( Peer::State_Ready, Peer::State_Dead ) ) break;
if( Peer::State_New == peer->setstate( Peer::State_New, Peer::State_Dead ) ) break;
if( Peer::State_Waiting == peer->setstate( Peer::State_Waiting, Peer::State_Dead ) ) break;
if( Peer::State_Error == peer->setstate( Peer::State_Error, Peer::State_Dead ) ) break;
peerMutex.unlock();
SleepEx(10, false);
}
// the mutex is still locked
char buf[128];
if(dbg) dprintf( "p2p: destroy peer %s\n", peer->remoteAddr.str(buf) );
for( auto ptr: peer->reliable ) { free(ptr); }
RBXASSERT( !peers.empty() );
RBXASSERT( index < peers.size() );
peers[index] = peers.back();
peers.resize( peers.size() - 1 );
async( peer->devAssoc->DestroyAsync() ).detach();
peer->devAssoc = nullptr;
peerMutex.unlock();
}
).detach();
}
void Network::connectPeer( PeerPtr peer, MultiplayerSessionMember^ member, boost::function<void(PeerPtr)> onConnected )
{
if( Peer::State_New != peer->setstate( Peer::State_New, Peer::State_Connecting ) )
RBXASSERT( !"oops" );
SecureDeviceAddress^ addr = SecureDeviceAddress::FromBase64String( member->SecureDeviceAddressBase64 );
auto devAssTemplate = this->assTemplate;
try
{
async( devAssTemplate->CreateAssociationAsync( addr, CreateSecureDeviceAssociationBehavior::Default ) )
.complete(
[peer]( SecureDeviceAssociation^ d ) mutable
{
peer->devAssoc = d;
}
).join();
}
catch(Platform::Exception^ e )
{
// maybe try again later?
peer->setstate( Peer::State_Connecting, Peer::State_Error );
return;
}
while(!peer->devAssoc)
{
if(1)
{
lock lck(peerMutex);
for( unsigned j = 0; j<pendingList.size(); ++j )
{
auto pendingAssoc = pendingList[j];
SecureDeviceAddress^ pendingAddr = pendingAssoc->RemoteSecureDeviceAddress;
if( 0 == addr->Compare(pendingAddr) )
{
peer->devAssoc = pendingAssoc;
pendingList[j] = pendingList.back();
pendingList.resize( pendingList.size() - 1);
break;
}
}
if(peer->devAssoc) break;
}
Sleep(10);
}
if(dbg) dprintf( "p2p: connected to: %S\n", peer->devAssoc->RemoteHostName->DisplayName->Data() );
peer->id = member->MemberId;
Platform::ArrayReference<BYTE> remoteSocketAddressBytes( (BYTE*)&peer->remoteAddr.rawdata, sizeof(peer->remoteAddr.rawdata) );
peer->devAssoc->GetRemoteSocketAddressBytes( remoteSocketAddressBytes );
// got the address, we can now send the data
peer->setstate( Peer::State_Connecting, Peer::State_Ready );
onConnected(peer);
}
// transmission control
void Network::controlThread()
{
unsigned peerItor = 0;
while( controlRunFlag )
{
Sleep(kRetransmitLoopMs);
// pick a peer
PeerPtr peer;
peerMutex.lock();
if( !peers.empty() )
peer = peers[ peerItor++ % peers.size() ];
peerMutex.unlock();
if(!peer)
continue;
// Acquire a lock on the peer
int oldstate;
while( 1 )
{
oldstate = peer->setstate( Peer::State_Ready, Peer::State_Busy2 );
if( oldstate == Peer::State_Ready ) break; // good
if( oldstate != Peer::State_Busy ) break; // bad
Sleep(1); // wait a bit and try again
}
if( oldstate != Peer::State_Ready )
continue; // the peer is not in an operational state, ignore
unsigned delUpTo = 0;
unsigned numSend = 0;
PacketHeader* toSend[kRetransmitMaxPackets] = {};
for( unsigned j=0, e=peer->reliable.size(); j<e && numSend < kRetransmitMaxPackets; ++j )
{
PacketHeader* packet = peer->reliable[j];
if( packet->seqR <= peer->rxackR )
{
delUpTo = j; // we got confirmation for this packet, discard
continue;
}
if( packet->timestamp + kRetransmitPeriodMs > GetTickCount() )
break; // the packet is not yet eligible for retry, and all following packets either, because they're ordered
toSend[numSend++] = packet;
}
if( delUpTo )
{
for( unsigned j=0; j<delUpTo; ++j )
{
if(dbg) { dprintf("p2p: removing reliable packet: "); dbgPrintPacket(peer->reliable[j] ); }
free(peer->reliable[j]);
}
peer->reliable.erase( peer->reliable.begin(), peer->reliable.begin() + delUpTo );
}
// unlock the peer, as the actual net send operations can be concurrent
if( Peer::State_Busy2 != peer->setstate(Peer::State_Busy2, Peer::State_Ready ) )
RBXASSERT( !"peer lock violation #2" );
// retransmit
for( unsigned j=0; j<numSend; ++j )
{
toSend[j]->timestamp = GetTickCount();
if(dbg) { dprintf("p2p: retransmit "); dbgPrintPacket(toSend[j]); }
int result = sock.send( peer->remoteAddr, toSend[j], toSend[j]->size, 10 );
if( result < 0 ) break; // error with the socket don't continue
}
}
}
enum Bool { True, False, IDunno };
}
+200
View File
@@ -0,0 +1,200 @@
#pragma once
// p2p.h - peer to peer UDP networking for voice
//
// This header is *very* toxic.
#include <wrl.h>
#include <xdk.h>
#include <vector>
#include <algorithm>
#include <mutex>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread.hpp>
#include <winsock2.h>
//#include <ws2def.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
#include <boost/function.hpp>
using namespace Microsoft::Xbox::Services::Multiplayer;
using namespace Windows::Xbox::Networking;
using namespace Windows::Foundation;
namespace Xp2p
{
struct PacketHeader;
class Peer;
typedef boost::shared_ptr<Peer> PeerPtr;
enum
{
kNetworkPort = 8700, // NOTE: check the manifest!
kMaxUdpSize = 1264, // what MS says in the XDK help
};
enum NetResult
{
Net_Ok,
Net_Fail = -1, // operation failed
Net_Timeout = -2, // operation timed out (you'll be getting quite a few of these)
Net_Peer = -3, // bad peer
Net_Retry = -4, // operation aborted because the peer was busy, the calling code should try again
Net_NotReady = -5, // operation aborted because the peer is not ready,
Net_Packet = -6, // bad incoming packet
};
enum PacketFlags
{
Packet_Default = 0,
Packet_Reliable = 1,
Packet_Ordered = 2,
};
struct Address
{
SOCKADDR_STORAGE rawdata;
Address();
Address(in6_addr addr, unsigned port);
sockaddr* toSockaddr() const { return (sockaddr*)&rawdata; }
int size() const { return sizeof(rawdata); }
in6_addr addr6() const { return ((sockaddr_in6&)rawdata).sin6_addr; }
unsigned port() const { return ntohs( ((sockaddr_in6&)rawdata).sin6_port ); }
char* str(char* to) const;
};
class Sock : public boost::noncopyable
{
int fd;
public:
Sock(unsigned port);
~Sock();
int send( const Address& to, const void* data, unsigned size, unsigned timeoutMs );
int recv( Address* from, void* data, unsigned size, unsigned timeoutMs );
};
class Peer : public boost::enable_shared_from_this<Peer>, boost::noncopyable
{
friend class Network;
friend void dbgPrintTx(PeerPtr p);
enum State { State_New, State_Connecting, State_Waiting, State_Ready, State_Busy, State_Busy2, State_Error, State_Dead };
volatile long state; // mutex and state indicator
SecureDeviceAssociation^ devAssoc; // device association (kinda like VPN transport layer between two consoles)
Address remoteAddr; // remote address as reported by devass
uint32 pingTime; // last ping time
uint32 id; // peer id (MultiplayerSessionMember::MemberId)
// transmission control, see comment below
uint32 txseq;
uint32 rxseq;
uint32 txseqR;
uint32 rxseqR;
uint32 rxackR;
std::vector<PacketHeader*> reliable; // retransmit queue for reliable packets
Peer();
int setstate( int expect, int replace );
public:
void* userData; // whatever you want to put in here
Platform::Object^ userObject; // or here
~Peer() {}
uint32 getPeerId() const { return id; }
};
/*
* TODO: write an essay
*
*/
//////////////////////////////////////////////////////////////////////////
// Packets
#include <pshpack1.h>
struct PacketHeader
{
// fill these out:
uint16 size; // entire packet size (incl. this header)
uint8 type; // type 0 is reserved, do not use!
// don't bother with these:
uint8 flags; // a combination of Packet_XXX
uint32 seq; // sequence # (all)
uint32 seqR; // sequence # (last reliable)
uint32 id; // peer id (MultiplayerSessionMember::MemberId)
uint32 timestamp;
uint8 reserved[32]; // reserved for now
};
// defines a packet of maximum length
// used to recv() an unknown packet
struct PacketStorage: PacketHeader
{
enum { MaxPayloadSize = kMaxUdpSize - sizeof(PacketHeader) };
uint8 payload[MaxPayloadSize];
};
#include <poppack.h>
//////////////////////////////////////////////////////////////////////////
// Network
class Network: public boost::noncopyable
{
typedef std::lock_guard<std::mutex> lock;
Sock sock;
uint32 myMemberId; // (MultiplayerSessionMember::MemberId)
SecureDeviceAssociationTemplate^ assTemplate;
Windows::Foundation::EventRegistrationToken incomingHandler;
volatile long controlRunFlag; // control thread run/exit flag
std::mutex peerMutex; // only used to manipulate these arrays; use Peer::setstate() to lock individual peers
std::vector< PeerPtr > peers;
std::vector< SecureDeviceAssociation^ > pendingList;
boost::thread controlThreadObject;
public:
Network( MultiplayerSessionMember^ currentUser );
~Network();
PeerPtr createPeer( MultiplayerSessionMember^ member, boost::function<void(PeerPtr)> onConnected );
void destroyPeer( PeerPtr peer );
// sends a packet to that peer
// returns number of bytes sent or -1 on error
NetResult sendPacket( PeerPtr peer, PacketHeader* packet, unsigned timeoutMs, unsigned flags );
// receives a packet
NetResult recvPacket( PacketStorage* stor, unsigned timeoutMs );
// MUST be called after each recvPacket
// figures our who sent this packet
NetResult processPacket( PeerPtr& who, PacketHeader* header );
private:
void connectPeer( PeerPtr peer, MultiplayerSessionMember^ member, boost::function<void(PeerPtr)> onConnected ); // call on a separate thread!
PeerPtr getPeerByAssoc( SecureDeviceAssociation^ incoming );
void controlThread();
};
}
+86
View File
@@ -0,0 +1,86 @@
#include "renderJob.h"
#include "v8datamodel/BaseRenderJob.h"
#include "v8datamodel/DataModel.h"
#include "rbx/rbxTime.h"
#include "GfxBase/ViewBase.h"
#include "GfxBase/FrameRateManager.h"
#include "RenderSettingsItem.h"
#include "marshaller.h"
#include "rbx/Profiler.h"
RenderJob::RenderJob(RBX::ViewBase* v, Marshaller* m)
: RBX::BaseRenderJob(CRenderSettingsItem::singleton().getMinFrameRate(), CRenderSettingsItem::singleton().getMaxFrameRate(), shared_from(v->getDataModel()) )
{
view = v;
marshaller = m;
stopped = 0;
}
void RenderJob::stop()
{
stopped = 1;
}
static void scheduleRenderPerform(const weak_ptr<RenderJob>& selfWeak, RBX::ViewBase* view, double timeJobStart)
{
if (shared_ptr<RenderJob> self = selfWeak.lock())
{
view->renderPerform(timeJobStart);
self->wake();
}
}
RBX::TaskScheduler::StepResult RenderJob::stepDataModelJob(const Stats& stats)
{
RBXPROFILER_SCOPE("Jobs", __FUNCTION__);
if (stopped)
{
return RBX::TaskScheduler::Done;
}
RBX::DataModel* dm = view->getDataModel();
RBX::FrameRateManager* frm = view->getFrameRateManager();
double seconds = 0.016;
if(1)
{
RBX::DataModel::scoped_write_request request(dm);
if(frm) seconds = frm->GetFrameTimeStats().getLatest() / 1000.f;
dm->renderStep(seconds);
if( frm )
frm->configureFrameRateManager(RBX::CRenderSettings::FrameRateManagerAuto, true);
isAwake = false;
seconds = RBX::Time::nowFastSec();
marshaller->execute( boost::bind(&RBX::ViewBase::renderPrepare, view, this) );
}
marshaller->submit(boost::bind(&scheduleRenderPerform, weak_from(this), view, seconds));
return RBX::TaskScheduler::Stepped;
}
RBX::Time::Interval RenderJob::sleepTime(const Stats& stats)
{
if (isAwake)
return computeStandardSleepTime(stats, maxFrameRate);
else
return RBX::Time::Interval::max();
}
std::string RenderJob::getMetric(const std::string& metric) const
{
return "";
}
double RenderJob::getMetricValue(const std::string& metric) const
{
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "v8datamodel/BaseRenderJob.h"
class Marshaller;
namespace RBX
{
class View;
class ViewBase;
}
// This job calls ViewBase::render(), which needs to be done exclusive to the
// DataModel. This is why it has the DataModelJob::Render enum, which
// prevents concurrent writes to DataModel. It also needs to run in the view's
// thread for OpenGL.
// TODO: Can Ogre be modified to not require the thread?
class RenderJob : public RBX::BaseRenderJob, public RBX::IMetric
{
Marshaller* marshaller;
RBX::ViewBase* view;
volatile int stopped;
public:
RenderJob(RBX::ViewBase* robloxView, Marshaller* marshaller);
virtual RBX::TaskScheduler::StepResult stepDataModelJob(const Stats& stats);
virtual RBX::Time::Interval RenderJob::sleepTime(const Stats& stats);
virtual std::string getMetric(const std::string& metric) const;
virtual double getMetricValue(const std::string& metric) const;
void stop();
};
+1
View File
@@ -0,0 +1 @@
"%DurangoXDK%"bin\xcetool Events-RBLX.0-1465F7BC.man -c xdpevents.h
+626
View File
@@ -0,0 +1,626 @@
//**********************************************************************`
//* This is an include file generated by EtwPlusTool. *`
//* *`
//* Copyright (c) Microsoft Corporation. All Rights Reserved. *`
//**********************************************************************`
#pragma once
#pragma pack(push, 16)
#include "EtwPlus.h"
#if defined(__cplusplus)
extern "C" {
#endif
// Field Descriptors, used in the ETX_EVENT_DESCRIPTOR array below
//
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_A_DeleteMe_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AvatarsEquipped_Fields[4] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_Int32,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_Award10DayRoll_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_Award20DayRoll_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_Award3DayRoll_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardDeepDiver_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardFoursCompany_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardOneNameManyFaces_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardPollster_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardSampler_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardStrengthInNumbers_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardWorldTraveler_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_AwardYouDidIt_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_CurrentAvatar_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_GameProgress_Fields[4] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_Float,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_GamesCount_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_MultiplayerRoundEnd_Fields[11] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_Int32,0},{EtxFieldType_GUID,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0},{EtxFieldType_Float,0},{EtxFieldType_Int32,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_MultiplayerRoundStart_Fields[9] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_Int32,0},{EtxFieldType_GUID,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_PartyCount_Fields[3] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_PlayerSessionEnd_Fields[7] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_PlayerSessionPause_Fields[4] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_UnicodeString,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_PlayerSessionResume_Fields[6] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0}};
EXTERN_C __declspec(selectany) ETX_FIELD_DESCRIPTOR RBLX_1465F7BC_PlayerSessionStart_Fields[6] = {{EtxFieldType_UnicodeString,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_GUID,0},{EtxFieldType_UnicodeString,0},{EtxFieldType_Int32,0},{EtxFieldType_Int32,0}};
// Event name mapping
//
#define A_DeleteMe_value 1
#define AvatarsEquipped_value 2
#define Award10DayRoll_value 3
#define Award20DayRoll_value 4
#define Award3DayRoll_value 5
#define AwardDeepDiver_value 6
#define AwardFoursCompany_value 7
#define AwardOneNameManyFaces_value 8
#define AwardPollster_value 9
#define AwardSampler_value 10
#define AwardStrengthInNumbers_value 11
#define AwardWorldTraveler_value 12
#define AwardYouDidIt_value 13
#define CurrentAvatar_value 14
#define GameProgress_value 15
#define GamesCount_value 16
#define MultiplayerRoundEnd_value 17
#define MultiplayerRoundStart_value 18
#define PartyCount_value 19
#define PlayerSessionEnd_value 20
#define PlayerSessionPause_value 21
#define PlayerSessionResume_value 22
#define PlayerSessionStart_value 23
// Event Descriptor array
//
EXTERN_C __declspec(selectany) ETX_EVENT_DESCRIPTOR RBLX_1465F7BCEvents[23] = {
{{ 1, 0, 0, 0, 0, 0, 0x0 }, "A_DeleteMe", "0.7.IGB-2.0", RBLX_1465F7BC_A_DeleteMe_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 2, 1, 0, 0, 0, 0, 0x0 }, "AvatarsEquipped", "0.7.IGB-2.1", RBLX_1465F7BC_AvatarsEquipped_Fields, 4, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 3, 0, 0, 0, 0, 0, 0x0 }, "Award10DayRoll", "0.7.IGB-2.0", RBLX_1465F7BC_Award10DayRoll_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 4, 0, 0, 0, 0, 0, 0x0 }, "Award20DayRoll", "0.7.IGB-2.0", RBLX_1465F7BC_Award20DayRoll_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 5, 0, 0, 0, 0, 0, 0x0 }, "Award3DayRoll", "0.7.IGB-2.0", RBLX_1465F7BC_Award3DayRoll_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 6, 0, 0, 0, 0, 0, 0x0 }, "AwardDeepDiver", "0.7.IGB-2.0", RBLX_1465F7BC_AwardDeepDiver_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 7, 0, 0, 0, 0, 0, 0x0 }, "AwardFoursCompany", "0.7.IGB-2.0", RBLX_1465F7BC_AwardFoursCompany_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 8, 0, 0, 0, 0, 0, 0x0 }, "AwardOneNameManyFaces", "0.7.IGB-2.0", RBLX_1465F7BC_AwardOneNameManyFaces_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 9, 0, 0, 0, 0, 0, 0x0 }, "AwardPollster", "0.7.IGB-2.0", RBLX_1465F7BC_AwardPollster_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 10, 0, 0, 0, 0, 0, 0x0 }, "AwardSampler", "0.7.IGB-2.0", RBLX_1465F7BC_AwardSampler_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 11, 0, 0, 0, 0, 0, 0x0 }, "AwardStrengthInNumbers", "0.7.IGB-2.0", RBLX_1465F7BC_AwardStrengthInNumbers_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 12, 0, 0, 0, 0, 0, 0x0 }, "AwardWorldTraveler", "0.7.IGB-2.0", RBLX_1465F7BC_AwardWorldTraveler_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 13, 0, 0, 0, 0, 0, 0x0 }, "AwardYouDidIt", "0.7.IGB-2.0", RBLX_1465F7BC_AwardYouDidIt_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 14, 0, 0, 0, 0, 0, 0x0 }, "CurrentAvatar", "0.7.IGB-2.0", RBLX_1465F7BC_CurrentAvatar_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 15, 0, 0, 0, 0, 0, 0x0 }, "GameProgress", "0.7.IGGP-2.0", RBLX_1465F7BC_GameProgress_Fields, 4, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 16, 0, 0, 0, 0, 0, 0x0 }, "GamesCount", "0.7.IGB-2.0", RBLX_1465F7BC_GamesCount_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 17, 0, 0, 0, 0, 0, 0x0 }, "MultiplayerRoundEnd", "0.7.IGMRE-2.0", RBLX_1465F7BC_MultiplayerRoundEnd_Fields, 11, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 18, 0, 0, 0, 0, 0, 0x0 }, "MultiplayerRoundStart", "0.7.IGMRS-2.0", RBLX_1465F7BC_MultiplayerRoundStart_Fields, 9, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 19, 0, 0, 0, 0, 0, 0x0 }, "PartyCount", "0.7.IGB-2.0", RBLX_1465F7BC_PartyCount_Fields, 3, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 20, 0, 0, 0, 0, 0, 0x0 }, "PlayerSessionEnd", "0.7.IGPSE-2.0", RBLX_1465F7BC_PlayerSessionEnd_Fields, 7, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 21, 0, 0, 0, 0, 0, 0x0 }, "PlayerSessionPause", "0.7.IGPSPA-2.0", RBLX_1465F7BC_PlayerSessionPause_Fields, 4, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 22, 0, 0, 0, 0, 0, 0x0 }, "PlayerSessionResume", "0.7.IGPSR-2.0", RBLX_1465F7BC_PlayerSessionResume_Fields, 6, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault },
{{ 23, 0, 0, 0, 0, 0, 0x0 }, "PlayerSessionStart", "0.7.IGPSS-2.0", RBLX_1465F7BC_PlayerSessionStart_Fields, 6, 0, EtxEventEnabledState_Undefined, EtxEventEnabledState_ProviderDefault, EtxPopulationSample_Undefined, EtxPopulationSample_UseProviderPopulationSample, EtxEventLatency_Undefined, EtxEventLatency_ProviderDefault, EtxEventPriority_Undefined, EtxEventPriority_ProviderDefault }};
// Provider Descriptor for RBLX_1465F7BC
//
EXTERN_C __declspec(selectany) ETX_PROVIDER_DESCRIPTOR RBLX_1465F7BCProvider = {"RBLX_1465F7BC", {0xc01cb476,0x5b6e,0x430d,{0xa9,0x07,0xcd,0x42,0x2e,0xfb,0x76,0x4a}}, 23, (ETX_EVENT_DESCRIPTOR*)&RBLX_1465F7BCEvents, 0, EtxProviderEnabledState_Undefined, EtxProviderEnabledState_OnByDefault, 0, 100, EtxProviderLatency_Undefined, EtxProviderLatency_RealTime, EtxProviderPriority_Undefined, EtxProviderPriority_Critical};
// ETW handle for RBLX_1465F7BC
//
EXTERN_C __declspec(selectany) REGHANDLE RBLX_1465F7BCHandle = (REGHANDLE)0;
/*++
Routine Description:
Register the provider with ETW+.
Arguments:
None
Remarks:
ERROR_SUCCESS if success or if the provider was already registered.
Otherwise, an error code.
--*/
#define EventRegisterRBLX_1465F7BC() EtxRegister(&RBLX_1465F7BCProvider, &RBLX_1465F7BCHandle)
/*++
Routine Description:
Unregister the provider from ETW+.
Arguments:
None
Remarks:
ERROR_SUCCESS if success or if the provider was not registered.
Otherwise, an error code.
--*/
#define EventUnregisterRBLX_1465F7BC() EtxUnregister(&RBLX_1465F7BCProvider, &RBLX_1465F7BCHandle)
#define EventEnabledA_DeleteMe() (TRUE)
// Entry point to log the event A_DeleteMe
//
__inline
ULONG
EventWriteA_DeleteMe(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_A_DeleteMe 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_A_DeleteMe];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[0], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_A_DeleteMe, EventData);
}
#define EventEnabledAvatarsEquipped() (TRUE)
// Entry point to log the event AvatarsEquipped
//
__inline
ULONG
EventWriteAvatarsEquipped(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId, __in const signed int AvatarsCount)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AvatarsEquipped 4
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AvatarsEquipped];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[3], &AvatarsCount, sizeof(AvatarsCount));
return EtxEventWrite(&RBLX_1465F7BCEvents[1], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AvatarsEquipped, EventData);
}
#define EventEnabledAward10DayRoll() (TRUE)
// Entry point to log the event Award10DayRoll
//
__inline
ULONG
EventWriteAward10DayRoll(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_Award10DayRoll 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_Award10DayRoll];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[2], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_Award10DayRoll, EventData);
}
#define EventEnabledAward20DayRoll() (TRUE)
// Entry point to log the event Award20DayRoll
//
__inline
ULONG
EventWriteAward20DayRoll(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_Award20DayRoll 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_Award20DayRoll];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[3], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_Award20DayRoll, EventData);
}
#define EventEnabledAward3DayRoll() (TRUE)
// Entry point to log the event Award3DayRoll
//
__inline
ULONG
EventWriteAward3DayRoll(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_Award3DayRoll 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_Award3DayRoll];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[4], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_Award3DayRoll, EventData);
}
#define EventEnabledAwardDeepDiver() (TRUE)
// Entry point to log the event AwardDeepDiver
//
__inline
ULONG
EventWriteAwardDeepDiver(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardDeepDiver 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardDeepDiver];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[5], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardDeepDiver, EventData);
}
#define EventEnabledAwardFoursCompany() (TRUE)
// Entry point to log the event AwardFoursCompany
//
__inline
ULONG
EventWriteAwardFoursCompany(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardFoursCompany 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardFoursCompany];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[6], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardFoursCompany, EventData);
}
#define EventEnabledAwardOneNameManyFaces() (TRUE)
// Entry point to log the event AwardOneNameManyFaces
//
__inline
ULONG
EventWriteAwardOneNameManyFaces(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardOneNameManyFaces 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardOneNameManyFaces];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[7], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardOneNameManyFaces, EventData);
}
#define EventEnabledAwardPollster() (TRUE)
// Entry point to log the event AwardPollster
//
__inline
ULONG
EventWriteAwardPollster(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardPollster 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardPollster];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[8], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardPollster, EventData);
}
#define EventEnabledAwardSampler() (TRUE)
// Entry point to log the event AwardSampler
//
__inline
ULONG
EventWriteAwardSampler(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardSampler 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardSampler];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[9], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardSampler, EventData);
}
#define EventEnabledAwardStrengthInNumbers() (TRUE)
// Entry point to log the event AwardStrengthInNumbers
//
__inline
ULONG
EventWriteAwardStrengthInNumbers(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardStrengthInNumbers 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardStrengthInNumbers];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[10], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardStrengthInNumbers, EventData);
}
#define EventEnabledAwardWorldTraveler() (TRUE)
// Entry point to log the event AwardWorldTraveler
//
__inline
ULONG
EventWriteAwardWorldTraveler(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardWorldTraveler 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardWorldTraveler];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[11], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardWorldTraveler, EventData);
}
#define EventEnabledAwardYouDidIt() (TRUE)
// Entry point to log the event AwardYouDidIt
//
__inline
ULONG
EventWriteAwardYouDidIt(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_AwardYouDidIt 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_AwardYouDidIt];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[12], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_AwardYouDidIt, EventData);
}
#define EventEnabledCurrentAvatar() (TRUE)
// Entry point to log the event CurrentAvatar
//
__inline
ULONG
EventWriteCurrentAvatar(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_CurrentAvatar 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_CurrentAvatar];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[13], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_CurrentAvatar, EventData);
}
#define EventEnabledGameProgress() (TRUE)
// Entry point to log the event GameProgress
//
__inline
ULONG
EventWriteGameProgress(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId, __in const float CompletionPercent)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_GameProgress 4
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_GameProgress];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[3], &CompletionPercent, sizeof(CompletionPercent));
return EtxEventWrite(&RBLX_1465F7BCEvents[14], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_GameProgress, EventData);
}
#define EventEnabledGamesCount() (TRUE)
// Entry point to log the event GamesCount
//
__inline
ULONG
EventWriteGamesCount(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_GamesCount 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_GamesCount];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[15], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_GamesCount, EventData);
}
#define EventEnabledMultiplayerRoundEnd() (TRUE)
// Entry point to log the event MultiplayerRoundEnd
//
__inline
ULONG
EventWriteMultiplayerRoundEnd(__in_opt PCWSTR UserId, __in LPCGUID RoundId, __in const signed int SectionId, __in LPCGUID PlayerSessionId, __in_opt PCWSTR MultiplayerCorrelationId, __in const signed int GameplayModeId, __in const signed int MatchTypeId, __in const signed int DifficultyLevelId, __in const float TimeInSeconds, __in const signed int ExitStatusId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_MultiplayerRoundEnd 11
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_MultiplayerRoundEnd];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], RoundId, sizeof(GUID));
EventDataDescCreate(&EventData[3], &SectionId, sizeof(SectionId));
EventDataDescCreate(&EventData[4], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[5], (MultiplayerCorrelationId != NULL) ? MultiplayerCorrelationId : L"", (MultiplayerCorrelationId != NULL) ? (ULONG)((wcslen(MultiplayerCorrelationId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[6], &GameplayModeId, sizeof(GameplayModeId));
EventDataDescCreate(&EventData[7], &MatchTypeId, sizeof(MatchTypeId));
EventDataDescCreate(&EventData[8], &DifficultyLevelId, sizeof(DifficultyLevelId));
EventDataDescCreate(&EventData[9], &TimeInSeconds, sizeof(TimeInSeconds));
EventDataDescCreate(&EventData[10], &ExitStatusId, sizeof(ExitStatusId));
return EtxEventWrite(&RBLX_1465F7BCEvents[16], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_MultiplayerRoundEnd, EventData);
}
#define EventEnabledMultiplayerRoundStart() (TRUE)
// Entry point to log the event MultiplayerRoundStart
//
__inline
ULONG
EventWriteMultiplayerRoundStart(__in_opt PCWSTR UserId, __in LPCGUID RoundId, __in const signed int SectionId, __in LPCGUID PlayerSessionId, __in_opt PCWSTR MultiplayerCorrelationId, __in const signed int GameplayModeId, __in const signed int MatchTypeId, __in const signed int DifficultyLevelId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_MultiplayerRoundStart 9
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_MultiplayerRoundStart];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], RoundId, sizeof(GUID));
EventDataDescCreate(&EventData[3], &SectionId, sizeof(SectionId));
EventDataDescCreate(&EventData[4], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[5], (MultiplayerCorrelationId != NULL) ? MultiplayerCorrelationId : L"", (MultiplayerCorrelationId != NULL) ? (ULONG)((wcslen(MultiplayerCorrelationId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[6], &GameplayModeId, sizeof(GameplayModeId));
EventDataDescCreate(&EventData[7], &MatchTypeId, sizeof(MatchTypeId));
EventDataDescCreate(&EventData[8], &DifficultyLevelId, sizeof(DifficultyLevelId));
return EtxEventWrite(&RBLX_1465F7BCEvents[17], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_MultiplayerRoundStart, EventData);
}
#define EventEnabledPartyCount() (TRUE)
// Entry point to log the event PartyCount
//
__inline
ULONG
EventWritePartyCount(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_PartyCount 3
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_PartyCount];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
return EtxEventWrite(&RBLX_1465F7BCEvents[18], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_PartyCount, EventData);
}
#define EventEnabledPlayerSessionEnd() (TRUE)
// Entry point to log the event PlayerSessionEnd
//
__inline
ULONG
EventWritePlayerSessionEnd(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId, __in_opt PCWSTR MultiplayerCorrelationId, __in const signed int GameplayModeId, __in const signed int DifficultyLevelId, __in const signed int ExitStatusId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionEnd 7
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionEnd];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[3], (MultiplayerCorrelationId != NULL) ? MultiplayerCorrelationId : L"", (MultiplayerCorrelationId != NULL) ? (ULONG)((wcslen(MultiplayerCorrelationId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[4], &GameplayModeId, sizeof(GameplayModeId));
EventDataDescCreate(&EventData[5], &DifficultyLevelId, sizeof(DifficultyLevelId));
EventDataDescCreate(&EventData[6], &ExitStatusId, sizeof(ExitStatusId));
return EtxEventWrite(&RBLX_1465F7BCEvents[19], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionEnd, EventData);
}
#define EventEnabledPlayerSessionPause() (TRUE)
// Entry point to log the event PlayerSessionPause
//
__inline
ULONG
EventWritePlayerSessionPause(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId, __in_opt PCWSTR MultiplayerCorrelationId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionPause 4
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionPause];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[3], (MultiplayerCorrelationId != NULL) ? MultiplayerCorrelationId : L"", (MultiplayerCorrelationId != NULL) ? (ULONG)((wcslen(MultiplayerCorrelationId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
return EtxEventWrite(&RBLX_1465F7BCEvents[20], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionPause, EventData);
}
#define EventEnabledPlayerSessionResume() (TRUE)
// Entry point to log the event PlayerSessionResume
//
__inline
ULONG
EventWritePlayerSessionResume(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId, __in_opt PCWSTR MultiplayerCorrelationId, __in const signed int GameplayModeId, __in const signed int DifficultyLevelId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionResume 6
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionResume];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[3], (MultiplayerCorrelationId != NULL) ? MultiplayerCorrelationId : L"", (MultiplayerCorrelationId != NULL) ? (ULONG)((wcslen(MultiplayerCorrelationId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[4], &GameplayModeId, sizeof(GameplayModeId));
EventDataDescCreate(&EventData[5], &DifficultyLevelId, sizeof(DifficultyLevelId));
return EtxEventWrite(&RBLX_1465F7BCEvents[21], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionResume, EventData);
}
#define EventEnabledPlayerSessionStart() (TRUE)
// Entry point to log the event PlayerSessionStart
//
__inline
ULONG
EventWritePlayerSessionStart(__in_opt PCWSTR UserId, __in LPCGUID PlayerSessionId, __in_opt PCWSTR MultiplayerCorrelationId, __in const signed int GameplayModeId, __in const signed int DifficultyLevelId)
{
#define ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionStart 6
EVENT_DATA_DESCRIPTOR EventData[ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionStart];
UINT8 scratch[64];
EtxFillCommonFields_v7(&EventData[0], scratch, 64);
EventDataDescCreate(&EventData[1], (UserId != NULL) ? UserId : L"", (UserId != NULL) ? (ULONG)((wcslen(UserId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[2], PlayerSessionId, sizeof(GUID));
EventDataDescCreate(&EventData[3], (MultiplayerCorrelationId != NULL) ? MultiplayerCorrelationId : L"", (MultiplayerCorrelationId != NULL) ? (ULONG)((wcslen(MultiplayerCorrelationId) + 1) * sizeof(WCHAR)) : (ULONG)sizeof(L""));
EventDataDescCreate(&EventData[4], &GameplayModeId, sizeof(GameplayModeId));
EventDataDescCreate(&EventData[5], &DifficultyLevelId, sizeof(DifficultyLevelId));
return EtxEventWrite(&RBLX_1465F7BCEvents[22], &RBLX_1465F7BCProvider, RBLX_1465F7BCHandle, ARGUMENT_COUNT_RBLX_1465F7BC_PlayerSessionStart, EventData);
}
#if defined(__cplusplus)
};
#endif
#pragma pack(pop)
+9
View File
@@ -0,0 +1,9 @@
How to update xdpevents.h
Go to XDP, expand RBLX.O Development on the sidebar, select Events & Stat Rules
Click Publish & Download, save the .man file as 'Events-RBLX.0-1465F7BC.man' in this directory.
From Durango XDK command prompt, run this command:
xdpevents.bat