Ryan Kistner avatar Ryan Kistner committed f6fde84

idler2/matchfordead

Comments (0)

Files changed (38)

Binary file added.

MatchForDead/MatchForDead.sln

+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MatchForDead", "MatchForDead\MatchForDead.vcproj", "{2FD778F0-20F0-4454-9B37-86D32C0A367C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2FD778F0-20F0-4454-9B37-86D32C0A367C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{2FD778F0-20F0-4454-9B37-86D32C0A367C}.Debug|Win32.Build.0 = Debug|Win32
+		{2FD778F0-20F0-4454-9B37-86D32C0A367C}.Release|Win32.ActiveCfg = Release|Win32
+		{2FD778F0-20F0-4454-9B37-86D32C0A367C}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

MatchForDead/MatchForDead/MatchForDead.vcproj

+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="MatchForDead"
+	ProjectGUID="{2FD778F0-20F0-4454-9B37-86D32C0A367C}"
+	RootNamespace="MatchForDead"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;..\..\Open Steamworks&quot;;..\..\boost_1_40_0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="steamclient.lib"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\..\"
+				DelayLoadDLLs="steamclient.dll"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="&quot;..\..\Open Steamworks&quot;;..\..\boost_1_40_0"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				PerUserRedirection="false"
+				AdditionalDependencies="steamclient.lib"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\..\"
+				DelayLoadDLLs="steamclient.dll"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\main.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

MatchForDead/MatchForDead/main.cpp

+#define STEAMWORKS_CLIENT_INTERFACES
+#define STEAM
+
+#include "steamworks.h"
+
+#include <boost/cstdlib.hpp>
+#include <boost/unordered_map.hpp>
+
+#include <iostream>
+#include <iomanip>
+
+#define APPID 500
+
+IClientEngine *clengine;
+IClientFriends *clfriends;
+
+ISteamClient008 *client;
+ISteamMatchmaking007 *matchmaking;
+ISteamUserStats006 *stats;
+ISteamUtils004 *utils;
+ISteamUser012 *steamuser;
+
+class APICallResult
+{
+public:
+	int callback;
+	int size;
+	uint8 *buff;
+
+public:
+	APICallResult(int callback, int size) : callback(callback), size(size) { buff = (uint8 *)malloc(size); };
+	~APICallResult() { free(buff); };
+};
+
+typedef boost::unordered_map<SteamAPICall_t, APICallResult *> APIRemapMap;
+APIRemapMap apiremap;
+
+#define REMAP_APICALL(A,T) apiremap.insert(APIRemapMap::value_type(A, new APICallResult(T::k_iCallback, sizeof(T))));
+
+
+
+void DefaultCallback( const CallbackMsg_t& callbackMsg );
+
+void HandleCallback( const CallbackMsg_t& callback )
+{
+	switch(callback.m_iCallback)
+	{
+		case LobbyMatchList_t::k_iCallback:
+			{
+				LobbyMatchList_t *list = (LobbyMatchList_t *)callback.m_pubParam;
+
+				std::cout << "[CLIENT] I see " << list->m_nLobbiesMatching << " lobbies." << std::endl;
+
+				for(int i = 0; i < list->m_nLobbiesMatching; i++)
+				{
+					CSteamID lobbyid = matchmaking->GetLobbyByIndex(i);
+					std::cout << "[CLIENT] Lobby " << i << " " << lobbyid << std::endl;
+				}
+
+				char c;
+				std::cout << "1) new lobby" << std::endl << "2) join lobby" << std::endl;
+				std::cin >> c;
+				switch(c)
+				{
+				case '1':
+					std::cout << std::endl << "[CLIENT] Creating our own lobby" << std::endl;
+					matchmaking->CreateLobby(k_ELobbyTypeFriendsOnly, 6); 
+				break;
+				case '2':
+					std::cout << std::endl << "lobby: ";
+					uint64 lobby;
+					std::cin >> lobby;
+					matchmaking->JoinLobby(lobby);
+				break;
+				}
+			}
+		break;
+		case LobbyCreated_t::k_iCallback:
+			{
+				LobbyCreated_t *create = (LobbyCreated_t *)callback.m_pubParam;
+
+				std::cout << "[CLIENT] Lobby created from server " << EnumString<EResult>::From(create->m_eResult) << " " << create->m_ulSteamIDLobby << std::endl;
+
+				int lobbydatacount = matchmaking->GetLobbyDataCount(create->m_ulSteamIDLobby);
+				std::cout << "num k/v " << lobbydatacount << std::endl;
+				for(int i = 0; i < lobbydatacount; i++)
+				{
+					char key[1024];
+					char value[1024];
+					matchmaking->GetLobbyDataByIndex(create->m_ulSteamIDLobby, i, (char *)&key, sizeof(key), (char *)&value, sizeof(value));
+					std::cout << i << " key: " << key << " value: " << value << std::endl;
+				}
+			}
+		break;
+		case LobbyEnter_t::k_iCallback:
+			{
+				LobbyEnter_t *enter = (LobbyEnter_t *)callback.m_pubParam;
+
+				std::cout << "[CLIENT] Entered lobby " << enter->m_ulSteamIDLobby << " chat " << EnumString<EChatRoomEnterResponse>::From(enter->m_EChatRoomEnterResponse) << " permissions " << enter->m_rgfChatPermissions << std::endl;
+
+				bool sent = matchmaking->SendLobbyChatMsg(enter->m_ulSteamIDLobby, "Test\0", 5);
+				std::cout << "[CLIENT] Sent message " << sent << std::endl;
+			}
+		break;
+		case LobbyDataUpdate_t::k_iCallback:
+			{
+				LobbyDataUpdate_t *data = (LobbyDataUpdate_t *)callback.m_pubParam;
+
+				std::cout << "[CLIENT] Lobby data update " << data->m_ulSteamIDLobby << " is lobby itself " << (data->m_ulSteamIDLobby == data->m_ulSteamIDMember) << std::endl;
+			}
+		break;
+		case LobbyChatMsg_t::k_iCallback:
+			{
+				LobbyChatMsg_t *chat = (LobbyChatMsg_t *)callback.m_pubParam;
+				CSteamID user = chat->m_ulSteamIDUser;
+
+				std::cout << "[CLIENT] Message in lobby " << chat->m_ulSteamIDLobby << " by user " << user << " of type " << EnumString<EChatEntryType>::From(chat->m_eChatEntryType) << " id " << chat->m_iChatID << std::endl;
+
+				CSteamID chatuser;
+				char buff[1024];
+				EChatEntryType entry;
+
+				matchmaking->GetLobbyChatEntry(chat->m_ulSteamIDLobby, chat->m_iChatID, &chatuser, &buff, sizeof(buff), &entry);
+				std::cout << "Message contents: " << buff << std::endl;
+
+				if(user != steamuser->GetSteamID())
+				{
+					uint32 perm = 0;
+					bool got = clfriends->GetChatRoomPermissions(chat->m_ulSteamIDLobby, &perm);
+					std::cout << "[CLIENT] " << got << " permissions " << perm << std::endl;
+
+					bool term = clfriends->KickChatMember(chat->m_ulSteamIDLobby, user);
+					std::cout << "[CLIENT] Let's get out of here" << term << std::endl;
+					//matchmaking->LeaveLobby(chat->m_ulSteamIDLobby);
+				}
+			}
+		break;
+		case LobbyChatUpdate_t::k_iCallback:
+			{
+				LobbyChatUpdate_t *chatup = (LobbyChatUpdate_t *)callback.m_pubParam;
+				CSteamID userchanged = chatup->m_ulSteamIDUserChanged;
+				CSteamID userchanger = chatup->m_ulSteamIDMakingChange;
+
+				std::cout << "[CLIENT] Lobby update " << chatup->m_ulSteamIDLobby << " for user " << userchanged << " by " << userchanger << " to " << chatup->m_rgfChatMemberStateChange << " removed " << std::endl;
+			}
+		break;
+		case LobbyKicked_t::k_iCallback:
+			{
+				LobbyKicked_t *kick = (LobbyKicked_t *)callback.m_pubParam;
+			
+				std::cout << "[CLIENT] Kicked from lobby " << kick->m_ulSteamIDLobby << " by " << CSteamID(kick->m_ulSteamIDAdmin) << std::endl;
+			}
+		break;
+
+		case 304:
+		break;
+
+		case SteamAPICallCompleted_t::k_iCallback:
+			{
+				SteamAPICallCompleted_t *call = (SteamAPICallCompleted_t *)callback.m_pubParam;
+
+				std::cout << "[CLIENT] Async call " << call->m_hAsyncCall << " completed. " << std::endl;
+
+				APIRemapMap::iterator iter = apiremap.find( call->m_hAsyncCall );
+				if(iter != apiremap.end())
+				{
+					bool failed = false;
+					APICallResult *res = iter->second;
+					
+					bool ok = utils->GetAPICallResult(call->m_hAsyncCall, res->buff, res->size, res->callback, &failed);
+
+					CallbackMsg_t newcallback;
+					newcallback.m_iCallback = res->callback;
+					newcallback.m_pubParam = res->buff;
+					newcallback.m_cubParam = res->size;
+
+					HandleCallback(newcallback);
+
+					delete res;
+					apiremap.erase(iter);
+
+					if(failed)
+					{
+						bool gotstatus = utils->IsAPICallCompleted(call->m_hAsyncCall, &failed);
+						ESteamAPICallFailure cf = utils->GetAPICallFailureReason(call->m_hAsyncCall);
+	
+						std::cout << "Failure: " << gotstatus << " " << failed << " " << EnumString<ESteamAPICallFailure>::From(cf) << std::endl;
+					}
+				}
+			}
+			break;
+		default:
+			DefaultCallback(callback);
+			break;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	SetEnvironmentVariable("SteamAppId", "500");
+
+	CSteamAPILoader apiloader;
+
+	CreateInterfaceFn clientFactory = apiloader.Load();
+	if(clientFactory == NULL)
+		return EXIT_FAILURE;
+
+	client = (ISteamClient008 *)clientFactory(STEAMCLIENT_INTERFACE_VERSION_008, NULL);
+	assert(client != NULL);
+
+	clengine = (IClientEngine *)clientFactory(CLIENTENGINE_INTERFACE_VERSION, NULL);
+	assert(clengine != NULL);
+
+	HSteamPipe pipe = client->CreateSteamPipe();
+	HSteamUser user = client->ConnectToGlobalUser(pipe);
+ 
+	if(!user || !pipe)
+	{
+		std::cerr << "Steam user/pipe could not be created." << std::endl;
+		return EXIT_FAILURE;
+	}
+
+	std::cout << "Created user " << user << " pipe " << pipe << std::endl;
+
+	
+	clfriends = (IClientFriends *)clengine->GetIClientFriends( user, pipe, CLIENTFRIENDS_INTERFACE_VERSION );
+
+	steamuser = (ISteamUser012 *)client->GetISteamUser( user, pipe, STEAMUSER_INTERFACE_VERSION_012 );
+	utils = (ISteamUtils004 *)client->GetISteamUtils( pipe, STEAMUTILS_INTERFACE_VERSION_004 );
+	assert( utils->GetAppID() == APPID );
+
+	matchmaking = (ISteamMatchmaking007 *)client->GetISteamMatchmaking( user, pipe, STEAMMATCHMAKING_INTERFACE_VERSION_007 );
+	stats = (ISteamUserStats006 *)client->GetISteamUserStats( user, pipe, STEAMUSERSTATS_INTERFACE_VERSION_006 );
+
+	matchmaking->RequestLobbyList();
+
+	while(true)
+	{
+		CallbackMsg_t callbackMsg;
+		HSteamCall steamCall;
+
+		client->RunFrame();
+
+		if ( Steam_BGetCallback( pipe, &callbackMsg, &steamCall ))
+		{
+			HandleCallback(callbackMsg);
+
+			Steam_FreeLastCallback( pipe );
+		}
+
+		Sleep(10);
+	}
+}
+
+void DefaultCallback( const CallbackMsg_t& callbackMsg )
+{
+	int32 callBack = callbackMsg.m_iCallback;
+	ECallbackType type = (ECallbackType)((callBack / 100) * 100);
+
+	std::cout << "[CLIENT] Unhandled Callback: " << callBack << ", Type: " << EnumString<ECallbackType>::From(type) << ", Size: " << callbackMsg.m_cubParam << std::endl;
+
+	int32 callSize = callbackMsg.m_cubParam;
+	unsigned char *data = callbackMsg.m_pubParam;
+	std::cout << "  ";
+
+	for (int i = 0; i < callSize; i++)
+	{
+		unsigned char value = data[i];
+	
+		std::cout << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (unsigned int)value;
+		std::cout << " ";
+	}
+
+	std::cout << std::resetiosflags(std::ios_base::hex | std::ios_base::uppercase) << std::endl;
+}

Open Steamworks.sln

 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
-		VisualSVNWorkingCopyRoot = 
+		VisualSVNWorkingCopyRoot = .
 	EndGlobalSection
 EndGlobal

idler2/CClientContext.cpp

+#include "CClientContext.h"
+
+bool CClientContext::Begin()
+{
+	connected = false;
+
+	fileLogger = new CFileLogger( "client_log.txt" );
+
+	std::cout << "[CLIENT] Initializing... ";
+
+	pipe = client->CreateSteamPipe();
+	if (!pipe)
+	{
+		std::cerr << "Steam pipe could not be created." << std::endl;
+		return false;
+	}
+
+	user = client->ConnectToGlobalUser(pipe);
+	if (!user)
+	{
+		std::cerr << "Steam user could not be created." << std::endl;
+		return false;
+	}
+
+	networking = (ISteamNetworking002 *)client->GetISteamNetworking( user, pipe, STEAMNETWORKING_INTERFACE_VERSION_002 );
+	if ( !networking )
+	{
+		std::cerr << "Unable to get " STEAMNETWORKING_INTERFACE_VERSION_002  << std::endl;
+		return false;
+	}
+
+	steamuser = (ISteamUser012 *)client->GetISteamUser( user, pipe, STEAMUSER_INTERFACE_VERSION_012 );
+	if ( !steamuser )
+	{
+		std::cerr << "Unable to get " STEAMUSER_INTERFACE_VERSION_012 << std::endl;
+		return false;
+	}
+
+	steamfriends = (ISteamFriends005 *)client->GetISteamFriends( user, pipe, STEAMFRIENDS_INTERFACE_VERSION_005 );
+	if ( !steamfriends )
+	{
+		std::cerr << "Unable to get " STEAMFRIENDS_INTERFACE_VERSION_005 << std::endl;
+		return false;
+	}
+
+	useritems = (ISteamUserItems003 *)client->GetISteamGenericInterface( user, pipe, STEAMUSERITEMS_INTERFACE_VERSION_003 );
+	if ( !useritems )
+	{
+		std::cerr << "Unable to get " STEAMUSERITEMS_INTERFACE_VERSION_003 << std::endl;
+		return false;
+	}
+
+	std::cout << "Complete! pipe: " << pipe << " user: " << user << std::endl;
+
+	clientSocket = networking->CreateConnectionSocket(remoteip, remoteport, 20);
+	if ( !clientSocket )
+	{
+		std::cerr << "Unable to create connection socket." << std::endl;
+		return false;
+	}
+
+	running = true;
+	lastping = time(0);
+	return true;
+}
+
+void CClientContext::Think()
+{
+	HandleNetworking();
+
+	if(time(0) > (lastping + PING_TIMEOUT))
+	{
+		std::cout << "[CLIENT] Lost connection to server." << std::endl;
+		running = false;
+	}
+}
+
+void CClientContext::HandleNetworking()
+{
+	uint32 dataSize;
+
+	if ( !networking->IsDataAvailableOnSocket( clientSocket, &dataSize ) )
+		return; // no data waiting
+
+	void *data = malloc( dataSize );
+
+	if ( !networking->RetrieveDataFromSocket( clientSocket, data, dataSize, &dataSize ) )
+	{
+		// data is waiting, but we're unable to read it
+		free( data );
+		return;
+	}
+
+	ENetworkMessage *eMsg = (ENetworkMessage *)data;
+
+	switch ( *eMsg )
+	{
+
+		case eServerConnectionDenied:
+			HandleNetConnectionDenied( (NetServerConnectionDenied_t *)data );
+			break;
+
+		case eServerSendInfo:
+			HandleNetSendInfo( (NetServerSendInfo_t *)data );
+			break;
+
+		case eServerClientAuthed:
+			HandleNetClientAuthed( (NetServerClientAuthed_t *)data );
+			break;
+
+		case eServerClientKicked:
+			HandleNetClientKicked( (NetServerClientKicked_t *)data );
+			break;
+
+		case eServerPingRequest:
+			HandleNetPingRequest( (NetServerPingRequest_t *)data );
+			break;
+
+		case eServerYourItemWas:
+			HandleNetNameResponse( (NetServerYourItemWas_t *)data );
+			break;
+
+		default:
+			std::cout << "[CLIENT] Recieved unexpected ENetworkMessage from server (" << *eMsg << ")" << std::endl;
+			std::cout << "  Your client is out of date." << std::endl;
+			break;
+	}
+
+	free( data );
+}
+
+void CClientContext::HandleCallback(const CallbackMsg_t &callback)
+{
+	switch(callback.m_iCallback)
+	{
+		case SteamServersConnected_t::k_iCallback:
+			std::cout << "[CLIENT] Connected to back-end." << std::endl;
+			break;
+
+		case BeginLogonRetry_t::k_iCallback:
+			std::cout << "[CLIENT] Attempting to reconnect to back-end..." << std::endl;
+			break;
+
+		case SteamServerConnectFailure_t::k_iCallback:
+			std::cout << "[CLIENT] Disconnected from steam back-end." << std::endl;
+			std::cout << "  The client will automatically reconnect when the back-end is available." << std::endl;
+			break;
+
+		case SocketStatusCallback_t::k_iCallback:
+			HandleCallbackSocketStatus( (SocketStatusCallback_t *)callback.m_pubParam );
+			break;
+
+		case UserItemCount_t::k_iCallback:
+			std::cout << "[CLIENT] I have " << ((UserItemCount_t *)callback.m_pubParam)->m_unCount << " items." << std::endl;
+			std::cout << "  You will be notified when you recieve a new item." << std::endl;
+			break;
+
+		case UserItemGranted_t::k_iCallback:
+			HandleCallbackUserItemGranted( (UserItemGranted_t *)callback.m_pubParam );
+			break;
+
+		case SteamAPICallCompleted_t::k_iCallback:
+		case PersonaStateChange_t::k_iCallback:
+			break;
+
+		default:
+			DefaultCallback( callback );
+			break;
+	}
+}
+
+void CClientContext::DefaultCallback( const CallbackMsg_t& callbackMsg )
+{
+	std::stringstream ss;
+
+	int32 callBack = callbackMsg.m_iCallback;
+	ECallbackType type = (ECallbackType)((callBack / 100) * 100);
+
+	std::cout << "[CLIENT] Unhandled Callback: " << callBack << ", Type: " << EnumString<ECallbackType>::From(type) << ", Size: " << callbackMsg.m_cubParam << std::endl;
+	ss << "[CLIENT] Unhandled Callback: " << callBack << ", Type: " << EnumString<ECallbackType>::From(type) << ", Size: " << callbackMsg.m_cubParam << std::endl;
+
+	int32 callSize = callbackMsg.m_cubParam;
+	unsigned char *data = callbackMsg.m_pubParam;
+	std::cout << "  ";
+	ss << "  ";
+	for (int i = 0; i < callSize; i++)
+	{
+		unsigned char value = data[i];
+	
+		std::cout << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (unsigned int)value;
+		std::cout << " ";
+
+		ss << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (unsigned int)value;
+		ss << " ";
+	}
+
+	std::cout << std::resetiosflags(std::ios_base::hex | std::ios_base::uppercase) << std::endl;
+	ss << std::resetiosflags(std::ios_base::hex | std::ios_base::uppercase) << std::endl;
+
+	fileLogger->Log( ss.str().c_str() );
+}
+
+void CClientContext::HandleCallbackUserItemGranted( UserItemGranted_t *pItemGranted )
+{
+	ItemID id = pItemGranted->m_itemID;
+	uint32 itemType, itemLevel, itemFlags, quantity, nbAttribs;
+	EItemQuality quality;
+
+	useritems->GetItemByID(id, &itemType, &itemLevel, &quality, &itemFlags, &quantity, &nbAttribs);
+
+	NetClientItemGranted_t granted;
+	granted.itemid = itemType;
+
+	std::stringstream ss;
+
+	std::cout << "[CLIENT] You have been granted an item! Retrieving name from server..." << std::endl;
+	std::cout << "  ID: " << id << ", Type: " << itemType << ", Level: " << itemLevel << std::endl;
+
+	ss << "[CLIENT] You have been granted an item! Retrieving name from server..." << std::endl;
+	ss << "  ID: " << id << ", Type: " << itemType << ", Level: " << itemLevel << std::endl;
+
+	fileLogger->Log( ss.str().c_str() );
+
+	if ( !networking->SendDataOnSocket( clientSocket, (void *)&granted, sizeof( granted ), true ) )
+	{
+		std::cout << "HandleCallbackUserItemGranted() - Unable to report to server!" << std::endl;
+		running = false;
+	}
+}
+
+void CClientContext::HandleCallbackSocketStatus( SocketStatusCallback_t *pSocketStatus )
+{
+	// handle various client socket situations
+	switch ( pSocketStatus->m_eSNetSocketState )
+	{	
+		case k_ESNetSocketStateTimeoutDuringConnect:
+			// connection timeout to destination server, so we exit out
+			running = false;
+			std::cout << "HandleSocketStatusCallback() - Unable to connect to destination server." << std::endl;
+			break;
+
+		case k_ESNetSocketStateConnected:
+			{
+				std::cout << "[CLIENT] Connected to server, initiating handshake..." << std::endl;
+				// we've connected, lets start our data handshake
+				NetClientInitConnection_t msg;
+				msg.clientProtocolVersion = IDLER_CLIENT_VERSION;
+
+				networking->SendDataOnSocket( clientSocket, (void *)&msg, sizeof( msg ), true );
+			}
+			break;
+
+		case k_ESNetSocketStateConnectionBroken:
+		case k_ESNetSocketStateRemoteEndDisconnected:
+			std::cout << "[CLIENT] Lost connection to remote server. (" << EnumString<ESNetSocketState>::From( (ESNetSocketState)pSocketStatus->m_eSNetSocketState ) << ")" << std::endl;
+			running = false;
+			break;
+
+		case k_ESNetSocketStateInitiated:
+		case k_ESNetSocketStateChallengeHandshake:
+			break;
+
+		default:
+			std::cout << "[CLIENT] Socket " << pSocketStatus->m_hListenSocket << " is now " << EnumString<ESNetSocketState>::From( (ESNetSocketState)pSocketStatus->m_eSNetSocketState ) << std::endl;
+			break;
+	}
+}
+
+void CClientContext::HandleNetConnectionDenied( NetServerConnectionDenied_t *pConnectionDenied )
+{
+	// handle various denial reasons
+	switch ( pConnectionDenied->denyReason )
+	{
+
+	case EDenyServerFull:
+		std::cout << "[CLIENT] Connection denied to server: Server is full." << std::endl;
+		break;
+
+	case EDenySteamIDBanned:
+		std::cout << "[CLIENT] Connection denied to server: You are banned." << std::endl;
+		break;
+
+	case EDenyAuthFailed:
+		std::cout << "[CLIENT] Connection denied to server: Authentication failure." << std::endl;
+		break;
+
+	case EDenySteamIDExists:
+		std::cout << "[CLIENT] Connection denied to server: SteamID is already present on server." << std::endl;
+		break;
+
+	case EDenyClientOutdated:
+		std::cout << "[CLIENT] Connection denied to server: Your client is out of date." << std::endl;
+		break;
+
+	default:
+		std::cout << "[CLIENT] Connection denied to server, but an invalid reason (" << pConnectionDenied->denyReason << ") was supplied." << std::endl;
+		std::cout << "  Your client is out of date." << std::endl;
+		break;
+
+	}
+
+	std::cout << "  Message: " << pConnectionDenied->optionalMessage << std::endl;
+
+	running = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 
+//		   
+//-----------------------------------------------------------------------------
+void CClientContext::HandleNetSendInfo( NetServerSendInfo_t *pSendInfo )
+{
+	// should maybe store this server info somewhere?
+	std::cout << "[CLIENT] Recieved server details. SteamID: " << pSendInfo->serverSteamID << ", VAC Secure: " << pSendInfo->vacSecure << std::endl;
+
+	std::cout << "[CLIENT] Authenticating with server..." << std::endl;
+
+	NetClientAuth_t auth;
+	auth.ticketLen = steamuser->InitiateGameConnection( (void *)&auth.authTicket, AUTHTICKET_SIZE, pSendInfo->serverSteamID, remoteip, remoteport, pSendInfo->vacSecure );
+	strncpy(auth.username, steamfriends->GetPersonaName(), sizeof(auth.username));
+
+	useritems->LoadItems();
+
+	if ( !auth.ticketLen )
+	{
+		// if InitiateGameConnection fails, we bail out
+		std::cout << "HandleNetSendInfo() - InitiateGameConnection failed." << std::endl;
+		running = false;
+		return;
+	}
+	
+	if ( !networking->SendDataOnSocket( clientSocket, (void *)&auth, sizeof( auth ), true ) )
+	{
+		// connection was interrupted during the authentication process
+		std::cout << "HandleNetSendInfo() - Unable to send authticket to server." << std::endl;
+		running = false;
+		return;
+	}
+}
+
+void CClientContext::HandleNetClientAuthed( NetServerClientAuthed_t *pClientAuthed )
+{
+	std::cout << "[CLIENT] Authentication completed." << std::endl;
+	std::cout << "[CLIENT]   MOTD: " << pClientAuthed->messageOfTheDay << std::endl;
+}
+
+void CClientContext::HandleNetClientKicked( NetServerClientKicked_t *pClientKicked )
+{
+	std::cout << "[CLIENT] You have been kicked from the server: " << pClientKicked->kickMessage << std::endl;
+	
+	running = false;
+	return;
+}
+
+void CClientContext::HandleNetPingRequest( NetServerPingRequest_t *pPing )
+{
+	//std::cout << "[CLIENT] Pong! (Server said " << pPing->itemsTotal << ")" << std::endl;
+
+	lastping = time(0);
+
+	NetClientPingReply_t pong;
+	if ( !networking->SendDataOnSocket( clientSocket, (void *)&pong, sizeof( pong ), true ) )
+	{
+		std::cout << "HandleNetPingRequest() - Unable to reply to server ping!" << std::endl;
+		running = false;
+	}
+
+	return;
+}
+
+void CClientContext::HandleNetNameResponse( NetServerYourItemWas_t *pItemName )
+{
+	std::stringstream ss;
+
+	std::cout << "[CLIENT] You got a: " << pItemName->itemName << std::endl;
+	ss << "[CLIENT] You got a: " << pItemName->itemName << std::endl;
+
+	fileLogger->Log( ss.str().c_str() );
+}
+
+void CClientContext::End()
+{
+	if(clientSocket)
+		networking->DestroySocket(clientSocket, false);
+
+	if(user)
+		client->ReleaseUser(pipe, user);
+	if(pipe)
+		client->ReleaseSteamPipe(pipe);
+
+	delete fileLogger;
+}

idler2/CClientContext.h

+#ifndef CCLIENTCONTEXT_H
+#define CCLIENTCONTEXT_H
+
+#include "Common.h"
+
+#define IDLER_CLIENT_VERSION 1
+
+class CClientContext : public IdlerContext
+{
+public:
+    virtual ~CClientContext() {};
+	CClientContext(ISteamClient008 *client, uint32 ip, uint16 port) : IdlerContext(client), remoteip(ip), remoteport(port), clientSocket(0) {};
+
+	bool Begin();
+	void End();
+	void Think();
+
+	void HandleCallback(const CallbackMsg_t &callback);
+
+private:
+	// callback handlers
+	void HandleCallbackSocketStatus( SocketStatusCallback_t *pSocketStatus );
+	void HandleCallbackUserItemGranted( UserItemGranted_t *pItemGranted );
+
+	void HandleNetworking();
+
+	// network handlers
+	void DefaultCallback( const CallbackMsg_t& callbackMsg );
+	void HandleNetConnectionDenied( NetServerConnectionDenied_t *pConnectionDenied );
+	void HandleNetSendInfo( NetServerSendInfo_t *pSendInfo );
+	void HandleNetClientAuthed( NetServerClientAuthed_t *pClientAuthed );
+	void HandleNetClientKicked( NetServerClientKicked_t *pClientKicked );
+	void HandleNetPingRequest( NetServerPingRequest_t *pPing );
+	void HandleNetNameResponse( NetServerYourItemWas_t *pItemName );
+
+	ISteamNetworking002 *networking;
+	ISteamUser012		*steamuser;
+	ISteamFriends005	*steamfriends;
+	ISteamUserItems003	*useritems;
+
+	CFileLogger *fileLogger;
+
+	uint32 remoteip;
+	uint16 remoteport;
+	SNetSocket_t clientSocket;
+
+	time_t lastping;
+	bool connected;
+};
+
+#endif //CCLIENTCONTEXT_H

idler2/CItemDB.cpp

+#include "CItemDB.h"
+
+typedef boost::unordered_map<uint16, std::string> ItemLookupMap;
+
+ItemLookupMap itemMap;
+
+bool CItemDB::LoadDB()
+{
+	std::fstream db("item.db", std::ios::binary | std::ios::in);
+
+	uint16 items = 0;
+	db.read((char *)&items, sizeof(items));
+
+	if(items == 0)
+	{
+		std::cerr << "Unable to load DB, empty!" << std::endl;
+		return false;
+	}
+
+	for(int i = 0; i < items; i++)
+	{
+		uint16 index;
+		uint8 len;
+		char buff[ITEM_MAXNAMELEN] = {0};
+
+		db.read((char *)&index, sizeof(index));
+		db.read((char *)&len, sizeof(len));
+		db.read((char *)&buff, len);
+		itemMap.insert( ItemLookupMap::value_type(index, buff) );
+	}
+
+	return true;
+}
+
+void CItemDB::DumpDB()
+{
+	for(ItemLookupMap::const_iterator iter = itemMap.begin(); iter != itemMap.end(); ++iter)
+	{
+		std::cout << (iter->first) << ": " << (iter->second) << std::endl;
+	}
+}
+
+std::string CItemDB::GetItemName(uint16 id)
+{
+	ItemLookupMap::const_iterator iter = itemMap.find( id );
+	if(iter != itemMap.end())
+	{
+		return iter->second;
+	}
+
+	return "UNKNOWN ITEM";
+}
+
+uint16 CItemDB::ItemCount()
+{
+	return itemMap.size();
+}
+#ifndef CITEMDB_H
+#define CITEMDB_H
+
+#include "Common.h"
+
+class CItemDB
+{
+public:
+	static bool LoadDB();
+	static void DumpDB();
+	static std::string GetItemName(uint16 id);
+	static uint16 ItemCount();
+};
+
+#endif

idler2/CServerContext.cpp

+#include "CServerContext.h"
+
+bool CServerContext::Begin()
+{
+	std::cout << "[SERVER] Loading item DB... ";
+
+	// load our items database for item id to name resolution
+	if( !CItemDB::LoadDB() )
+		return false;
+
+	fileLogger = new CFileLogger( "server_log.txt" );
+
+	std::cout << "Loaded." << std::endl << "[SERVER] Initializing... ";
+
+
+	pipe = client->CreateSteamPipe();
+	client->SetLocalIPBinding(bindip, serverport-100);
+
+	std::cout << "Pipe " << pipe << " Account type " << k_EAccountTypeGameServer << std::endl;
+
+	user = client->CreateLocalUser(&pipe, (EAccountType)3); //k_EAccountTypeGameServer);
+	if (!user)
+	{
+		std::cerr << "Steam user could not be created." << std::endl;
+		return false;
+	}
+
+	masterserver = (ISteamMasterServerUpdater001 *)client->GetISteamMasterServerUpdater(user, pipe, STEAMMASTERSERVERUPDATER_INTERFACE_VERSION_001);
+	if (!masterserver)
+	{
+		std::cerr << "Unable to get " STEAMMASTERSERVERUPDATER_INTERFACE_VERSION_001 << std::endl;
+		return false;
+	}
+
+	gameserver = (ISteamGameServer009 *)client->GetISteamGameServer(user, pipe, STEAMGAMESERVER_INTERFACE_VERSION_009);
+	if (!gameserver)
+	{
+		std::cerr << "Unable to get " STEAMGAMESERVER_INTERFACE_VERSION_009 << std::endl;
+		return false;
+	}
+
+	gameserveritems = (ISteamGameServerItems004 *)client->GetISteamGenericInterface(user, pipe, STEAMGAMESERVERITEMS_INTERFACE_VERSION_004);
+	if (!gameserveritems)
+	{
+		std::cerr << "Unable to get " STEAMGAMESERVERITEMS_INTERFACE_VERSION_004 << std::endl;
+		return false;
+	}
+
+	networking = (ISteamNetworking002 *)client->GetISteamNetworking( user, pipe, STEAMNETWORKING_INTERFACE_VERSION_002 );
+	if (!networking)
+	{
+		std::cerr << "Unable to get " STEAMNETWORKING_INTERFACE_VERSION_002 << std::endl;
+		return false;
+	}
+
+	bool serverInit = gameserver->SetServerType(SERVER_FLAGS, 0, serverport, 0, serverport-1, "tf", "1.0.7.1", false);
+	if (!serverInit)
+	{
+		std::cerr << "Error initializing SteamGameServer type." << std::endl;
+		return false;
+	}
+
+	serverSocket = networking->CreateListenSocket( 0, 0, serverport, false );
+	if ( !serverSocket )
+	{
+		std::cerr << "Unable to create listen socket." << std::endl;
+		return false;
+	}
+
+	UpdateServerStatus();
+	masterserver->SetActive(true);
+
+	gameserver->LogOn();
+
+	std::cout << "Complete. pipe: " << pipe << " user: " << user << std::endl;
+
+	running = true;
+	lastping = time(0);
+
+	return true;
+}
+
+
+void CServerContext::RemoveUser(CUser *user)
+{
+	gameserver->SendUserDisconnect(user->GetSteamID());
+
+	clientSocketMap.erase( user->GetSocket() );
+	clientSteamMap.erase( user->GetSteamID() );
+	numClients--;
+
+	delete user;
+}
+
+void CServerContext::SendPingRequest()
+{
+	NetServerPingRequest_t msg;
+	msg.itemsTotal = 0;
+
+	//std::cout << "[SERVER] Ping?" << std::endl;
+
+	SocketUserMap::iterator iter = clientSocketMap.begin();
+	while(iter != clientSocketMap.end())
+	{
+		SNetSocket_t socket = iter->first;
+		CUser *user = iter->second;
+
+		if(user->GetPongTime() < lastping)
+		{
+			std::cout << "[SERVER] Dropping " << *user << " due to ping timeout." << std::endl;
+
+			// they haven't responded between the last ping and now
+			iter = clientSocketMap.erase( iter );
+
+			networking->DestroySocket(socket, false);
+			RemoveUser(user);
+			continue;
+		}
+
+		networking->SendDataOnSocket( socket, (void *)&msg, sizeof( NetServerPingRequest_t ), true );
+		++iter;
+	}
+
+	lastping = time(0);
+}
+
+void CServerContext::Think()
+{
+	HandleNetworking();
+
+	UpdateServerStatus();
+
+	if(time(0) >= lastping + PING_INTERVAL)
+		SendPingRequest();
+}
+
+void CServerContext::HandleNetworking()
+{
+	uint32 dataSize;
+	SNetSocket_t socketFrom;
+
+	if ( !networking->IsDataAvailable( serverSocket, &dataSize, &socketFrom ) )
+		return;
+
+	void *data = malloc( dataSize );
+
+	if ( !networking->RetrieveDataFromSocket( socketFrom, data, dataSize, &dataSize ) )
+	{
+		std::cout << "[SERVER] Error reading data from socket." << std::endl;
+		free( data );
+		return;
+	}
+
+	if ( dataSize < sizeof( ENetworkMessage ) )
+	{
+		std::cout << "[SERVER] Garbage data received." << std::endl;
+		free( data );
+		return;
+	}
+
+	ENetworkMessage *netMessage = (ENetworkMessage *)data;
+
+	switch ( *netMessage )
+	{
+
+	case eClientInitConnection:
+		HandleNetClientInitConnection( socketFrom, (NetClientInitConnection_t *)data);
+		break;
+
+	case eClientAuth:
+		HandleNetClientAuth( socketFrom, (NetClientAuth_t *)data );
+		break;
+
+	case eClientPingReply:
+		HandleNetClientPingReply( socketFrom, (NetClientPingReply_t *)data );
+		break;
+
+	case eClientItemGranted:
+		HandleNetClientItemGranted( socketFrom, (NetClientItemGranted_t *)data );
+		break;
+
+	default:
+		std::cout << "[SERVER] Recieved garbage data." << std::endl;
+		break;
+
+	}
+
+
+	free( data );
+}
+
+void CServerContext::DefaultCallback( const CallbackMsg_t& callbackMsg )
+{
+	std::stringstream ss;
+
+	int32 callBack = callbackMsg.m_iCallback;
+	ECallbackType type = (ECallbackType)((callBack / 100) * 100);
+
+	std::cout << "[SERVER] Unhandled Callback: " << callBack << ", Type: " << EnumString<ECallbackType>::From(type) << ", Size: " << callbackMsg.m_cubParam << std::endl;
+	ss << "[SERVER] Unhandled Callback: " << callBack << ", Type: " << EnumString<ECallbackType>::From(type) << ", Size: " << callbackMsg.m_cubParam << std::endl;
+
+	int32 callSize = callbackMsg.m_cubParam;
+	unsigned char *data = callbackMsg.m_pubParam;
+	std::cout << "  ";
+	ss << "  ";
+	for (int i = 0; i < callSize; i++)
+	{
+		unsigned char value = data[i];
+
+		std::cout << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (unsigned int)value;
+		std::cout << " ";
+
+		ss << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (unsigned int)value;
+		ss << " ";
+	}
+
+	std::cout << std::resetiosflags(std::ios_base::hex | std::ios_base::uppercase) << std::endl;
+	ss << std::resetiosflags(std::ios_base::hex | std::ios_base::uppercase) << std::endl;
+
+	fileLogger->Log( ss.str().c_str() );
+}
+
+void CServerContext::HandleCallback( const CallbackMsg_t &callback )
+{
+	switch(callback.m_iCallback)
+	{
+		case SteamServersConnected_t::k_iCallback:
+			std::cout << "[SERVER] Connected to steam back-end." << std::endl;
+			UpdateServerStatus();
+			break;
+
+		case SteamServerConnectFailure_t::k_iCallback:
+			std::cout << "[SERVER] Lost connection to steam back-end." << std::endl;
+			std::cout << "  Connection will be regained as soon as it is available." << std::endl;
+			break;
+
+		case SocketStatusCallback_t::k_iCallback:
+			HandleCallbackSocketStatus( (SocketStatusCallback_t *)callback.m_pubParam );
+			break;
+
+		case GSPolicyResponse_t::k_iCallback:
+			HandleCallbackPolicyResponse( (GSPolicyResponse_t *)callback.m_pubParam );
+			break;
+
+		case GSClientKick_t::k_iCallback:
+			HandleCallbackClientKick( (GSClientKick_t *)callback.m_pubParam );
+			break;
+
+		case GSClientDeny_t::k_iCallback:
+			HandleCallbackClientDeny( (GSClientDeny_t *)callback.m_pubParam );
+			break;
+
+		case GSClientApprove_t::k_iCallback:
+			HandleCallbackClientApprove( (GSClientApprove_t *)callback.m_pubParam );
+			break;
+
+		case GSItemCount_t::k_iCallback:
+			HandleCallbackItemCount( (GSItemCount_t *)callback.m_pubParam );
+			break;
+
+		case GSItemGranted_t::k_iCallback:
+			HandleCallbackItemGranted( (GSItemGranted_t *)callback.m_pubParam );
+			break;
+
+		case SteamAPICallCompleted_t::k_iCallback:
+			break;
+
+		default:
+			DefaultCallback( callback );
+			break;
+	}
+}
+
+void CServerContext::UpdateServerStatus()
+{
+	gameserver->UpdateServerStatus( numClients, MAX_CLIENTS, 0, "Team Fortress 2", "", "ctf_2fort" );
+	masterserver->SetBasicServerData( 7, true, "255", "tf", MAX_CLIENTS, false, "Team Fortress" );
+
+	for(SteamUserMap::const_iterator iter = clientSteamMap.begin(); iter != clientSteamMap.end(); ++iter)
+	{
+		CUser *user = iter->second;
+
+		if ( !gameserver->UpdateUserData(user->GetSteamID(), user->GetUsername().c_str(), 0) )
+		{
+			std::cout << "[SERVER] Unable to update data for client \"" << user->GetUsername() << "\" (" << user->GetSteamID() << ")" << std::endl;
+		}
+	}
+}
+
+
+void CServerContext::HandleCallbackSocketStatus( SocketStatusCallback_t *pSocketStatus )
+{
+	if ( pSocketStatus->m_hListenSocket != serverSocket )
+		return;
+
+	if ( pSocketStatus->m_eSNetSocketState >= k_ESNetSocketStateDisconnecting )
+	{
+		SocketUserMap::iterator iter = clientSocketMap.find( pSocketStatus->m_hSocket );
+		if( iter != clientSocketMap.end() )
+		{
+			CUser *user = iter->second;
+			std::cout << "[SERVER] Client " << *user << " has disconnected." << std::endl;
+
+			RemoveUser(user);
+		}
+
+		return;
+	}
+
+	if ( pSocketStatus->m_eSNetSocketState == k_ESNetSocketStateConnected )
+		return; // we can ignore these
+
+	std::cout << "[SERVER] Socket " << pSocketStatus->m_hListenSocket << " is now in state: " << EnumString<ESNetSocketState>::From( (ESNetSocketState)pSocketStatus->m_eSNetSocketState ) << std::endl;
+}
+
+void CServerContext::HandleCallbackPolicyResponse( GSPolicyResponse_t *pPolicyResponse )
+{
+	bool vacSecure = !!pPolicyResponse->m_bSecure;
+	std::cout << "  VAC Secure mode " << ( vacSecure ? "enabled" : "disabled" ) << "." << std::endl;
+}
+void CServerContext::HandleCallbackClientKick( GSClientKick_t *pClientKick )
+{
+	std::cout << "[SERVER] Back-end is requesting the kick of " << pClientKick->m_SteamID << ": " << EnumString<EDenyReason>::From( pClientKick->m_eDenyReason ) << std::endl;
+
+	// kick the user?
+
+}
+void CServerContext::HandleCallbackClientDeny( GSClientDeny_t *pClientDeny )
+{
+	std::cout << "[SERVER] Back-end is denying " << pClientDeny->m_SteamID << ": " << EnumString<EDenyReason>::From( pClientDeny->m_eDenyReason ) << std::endl;
+	std::cout << "  Message: " << pClientDeny->m_pchOptionalText << std::endl;
+
+	// kick the user?
+}
+void CServerContext::HandleCallbackClientApprove( GSClientApprove_t *pClientApprove )
+{
+	std::cout << "[SERVER] Back-end approved " << pClientApprove->m_SteamID << std::endl;
+
+	SteamUserMap::iterator iter = clientSteamMap.find( pClientApprove->m_SteamID );
+	if( iter != clientSteamMap.end() )
+	{
+		CUser *user = iter->second;
+		std::cout << "[SERVER] User " << *user << " was authed, updating user data." << std::endl;
+		gameserver->UpdateUserData(user->GetSteamID(), user->GetUsername().c_str(), 0);
+
+		gameserveritems->LoadItems(user->GetSteamID());
+	}
+}
+
+void CServerContext::HandleCallbackItemCount( GSItemCount_t *pClientItems )
+{
+	SteamUserMap::iterator iter = clientSteamMap.find( pClientItems->m_steamID );
+	if( iter != clientSteamMap.end() )
+	{
+		CUser *user = iter->second;
+		std::cout << "[SERVER] Loaded items for " << *user << ", " << pClientItems->m_unCount << " items." << std::endl;
+	}
+}
+void CServerContext::HandleCallbackItemGranted( GSItemGranted_t *pItemGranted )
+{
+	// todo: implement this instead of asking the client what item they got
+}
+
+void CServerContext::HandleNetClientInitConnection( SNetSocket_t clientSocket, NetClientInitConnection_t *pClientInit )
+{
+	if ( pClientInit->clientProtocolVersion < IDLER_SERVER_VERSION )
+	{
+		NetServerConnectionDenied_t denyMsg;
+		denyMsg.denyReason = EDenyClientOutdated;
+
+		char optMessage[256];
+		sprintf( optMessage, "Your client version (%d) is outdated. Server is version (%d).", pClientInit->clientProtocolVersion, IDLER_SERVER_VERSION );
+		strcpy( denyMsg.optionalMessage, optMessage );
+
+		networking->SendDataOnSocket( clientSocket, (void *)&denyMsg, sizeof( denyMsg ), true );
+		return;
+	}
+
+	NetServerSendInfo_t msg;
+
+	msg.serverSteamID = gameserver->GetSteamID();
+	msg.vacSecure = gameserver->Secure();
+
+	networking->SendDataOnSocket( clientSocket, (void *)&msg, sizeof( NetServerSendInfo_t ), true );
+}
+void CServerContext::HandleNetClientAuth( SNetSocket_t clientSocket, NetClientAuth_t *pClientAuth )
+{
+	if( clientSocketMap.find( clientSocket ) != clientSocketMap.end() )
+	{
+		return;
+	}
+
+	if ( numClients >= MAX_CLIENTS )
+	{
+		NetServerConnectionDenied_t denyMsg;
+		denyMsg.denyReason = EDenyServerFull;
+
+		networking->SendDataOnSocket( clientSocket, (void *)&denyMsg, sizeof( denyMsg ), true );
+		return;
+	}
+
+	uint32 clientIP;
+	networking->GetSocketInfo( clientSocket, NULL, NULL, &clientIP, NULL );
+
+	CSteamID clientSteamID;
+	EConnectionDenyReason denyReason = EDenyAuthFailed;
+	bool passedAuth = gameserver->SendUserConnectAndAuthenticate( clientIP, pClientAuth->authTicket, pClientAuth->ticketLen, &clientSteamID );
+
+	if( clientSteamMap.find( clientSteamID ) != clientSteamMap.end() )
+	{
+		passedAuth = false;
+		denyReason = EDenySteamIDExists;
+	}
+
+	if ( !passedAuth )
+	{
+		NetServerConnectionDenied_t denyMsg;
+		denyMsg.denyReason = denyReason;
+
+		networking->SendDataOnSocket( clientSocket, (void *)&denyMsg, sizeof( denyMsg ), true );
+
+		return;
+	}
+
+	CUser *user = new CUser(clientSocket, clientSteamID, pClientAuth->username);
+
+	clientSocketMap.insert( SocketUserMap::value_type( clientSocket, user ) );
+	clientSteamMap.insert( SteamUserMap::value_type( user->GetSteamID(), user ) );
+	numClients++;
+
+	UpdateServerStatus();
+
+	std::cout << "[SERVER] " << *user << " connected. Clients: " << numClients << ", Max Clients: " << MAX_CLIENTS << std::endl;
+
+	NetServerClientAuthed_t authedMsg;
+	strcpy( authedMsg.messageOfTheDay, "Welcome to an idler2 server. Please report any bugs and issues to: VoiDeD @ irc.gamesurge.net / #opensteamworks" );
+
+	networking->SendDataOnSocket( clientSocket, (void *)&authedMsg, sizeof( authedMsg ), true );
+}
+
+void CServerContext::HandleNetClientPingReply( SNetSocket_t clientSocket, NetClientPingReply_t *pClientPong )
+{
+	SocketUserMap::iterator iter = clientSocketMap.find( clientSocket );
+
+	if( iter == clientSocketMap.end() )
+		return;
+
+	CUser *user = iter->second;
+	user->PongResponse();
+
+	//std::cout << "[SERVER] User " << *user << ": Pong!" << std::endl;
+}
+
+void CServerContext::HandleNetClientItemGranted( SNetSocket_t clientSocket, NetClientItemGranted_t *pClientItemGranted )
+{
+	SocketUserMap::iterator iter = clientSocketMap.find( clientSocket );
+
+	if( iter == clientSocketMap.end() )
+		return;
+
+	CUser *user = iter->second;
+
+	std::string name = CItemDB::GetItemName(pClientItemGranted->itemid);
+
+	NetServerYourItemWas_t itemResponse;
+	strncpy(itemResponse.itemName, name.c_str(), sizeof(itemResponse.itemName));
+
+	networking->SendDataOnSocket( clientSocket, (void *)&itemResponse, sizeof( itemResponse ), true );
+
+	std::stringstream ss;
+
+	ss << "[SERVER] User " << *user << " got a " << name << " (" << pClientItemGranted->itemid << ")" << std::endl;
+	std::cout << "[SERVER] User " << *user << " got a " << name << " (" << pClientItemGranted->itemid << ")" << std::endl;
+
+	fileLogger->Log( ss.str().c_str() );
+}
+
+void CServerContext::End()
+{
+	SocketUserMap::iterator iter = clientSocketMap.begin();
+	while( iter != clientSocketMap.end() )
+	{
+		SNetSocket_t socket = iter->first;
+		CUser *user = iter->second;
+
+		iter = clientSocketMap.erase( iter );
+
+		networking->DestroySocket(socket, true);
+		RemoveUser(user);
+	}
+
+	if(serverSocket)
+		networking->DestroyListenSocket(serverSocket, true);
+
+	if(masterserver)
+		masterserver->SetActive(false);
+	if(gameserver)
+		gameserver->LogOff();
+
+	if(user)
+		client->ReleaseUser(pipe, user);
+	if(pipe)
+		client->ReleaseSteamPipe(pipe);
+}

idler2/CServerContext.h

+#ifndef CSERVERCONTEXT_H
+#define CSERVERCONTEXT_H
+
+#include "Common.h"
+#include "CUser.h"
+#include "CItemDB.h"
+
+#ifdef _WIN32
+#define SERVER_FLAGS k_unServerFlagDedicated | k_unServerFlagActive
+#else
+#define SERVER_FLAGS k_unServerFlagDedicated | k_unServerFlagActive | k_unServerFlagLinux
+#endif
+
+struct SteamHash : public std::unary_function<CSteamID, size_t> {
+    size_t operator()(const CSteamID& f) const {
+		return boost::hash<uint64>()(f.ConvertToUint64());
+    }
+};
+
+typedef boost::unordered_map<SNetSocket_t, CUser *> SocketUserMap;
+typedef boost::unordered_map<CSteamID, CUser *, SteamHash> SteamUserMap;
+
+#define IDLER_SERVER_VERSION 1
+
+class CServerContext : public IdlerContext
+{
+public:
+    virtual ~CServerContext() {};
+	CServerContext(ISteamClient008 *client, uint32 bindaddress, uint16 port) : IdlerContext(client), gameserver(NULL), masterserver(NULL), bindip(bindaddress), serverport(port), serverSocket(0), numClients(0) {}
+	bool Begin();
+	void End();
+	void Think();
+
+	void HandleCallback(const CallbackMsg_t &callback);
+
+
+
+private:
+	// callback handlers
+	void DefaultCallback( const CallbackMsg_t& callbackMsg );
+	void HandleCallbackSocketStatus( SocketStatusCallback_t *pSocketStatus );
+	void HandleCallbackPolicyResponse( GSPolicyResponse_t *pPolicyResponse );
+	void HandleCallbackClientKick( GSClientKick_t *pClientKick );
+	void HandleCallbackClientDeny( GSClientDeny_t *pClientDeny );
+	void HandleCallbackClientApprove( GSClientApprove_t *pClientApprove );
+	void HandleCallbackItemCount( GSItemCount_t *pClientItems );
+	void HandleCallbackItemGranted( GSItemGranted_t *pItemGranted );
+
+	void HandleNetworking();
+
+	// networking callbacks
+	void HandleNetClientInitConnection( SNetSocket_t clientSocket, NetClientInitConnection_t *pClientInit );
+	void HandleNetClientAuth( SNetSocket_t clientSocket, NetClientAuth_t *pClientAuth );
+	void HandleNetClientPingReply( SNetSocket_t clientSocket, NetClientPingReply_t *pClientPong );
+	void HandleNetClientItemGranted( SNetSocket_t clientSocket, NetClientItemGranted_t *pClientItemGranted );
+
+	void UpdateServerStatus();
+
+	void RemoveUser(CUser *user);
+	void SendPingRequest();
+
+	ISteamGameServer009			 *gameserver;
+	ISteamMasterServerUpdater001 *masterserver;
+	ISteamNetworking002			 *networking;
+	ISteamGameServerItems004	 *gameserveritems;
+
+	CFileLogger *fileLogger;
+
+	uint32 bindip;
+	uint16 serverport;
+	SNetListenSocket_t serverSocket;
+
+	time_t lastping;
+
+	uint32 numClients;
+	SocketUserMap clientSocketMap;
+	SteamUserMap  clientSteamMap;
+};
+
+#endif //CSERVERCONTEXT_H
+#include "CUser.h"
+
+std::ostream& operator<<(std::ostream& out, const CUser& u)
+{
+	out << u.GetUsername() << " (" << u.GetSteamID() << ")";
+	return out;
+}
+#ifndef CUSER_H
+#define CUSER_H
+
+#include "Common.h"
+
+class CUser
+{
+private:
+	CSteamID		steamID;
+	SNetSocket_t	socket;
+	std::string		username;
+	time_t			lastpong;
+
+public:
+	CUser(SNetSocket_t s, const CSteamID &steam, const std::string &user) : steamID(steam), socket(s), username(user), lastpong(time(0)) {};
+
+	const std::string&	GetUsername() const { return username; };
+	const CSteamID&		GetSteamID() const { return steamID; };
+	SNetSocket_t		GetSocket() const { return socket; };
+	time_t				GetPongTime() const { return lastpong; };
+
+	void				PongResponse() { lastpong = time(0); };
+};
+
+std::ostream& operator<<(std::ostream& out, const CUser& u);
+
+#endif
+#ifndef COMMON_H
+#define COMMON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#define APPID 440
+
+#define DEFAULT_PORT 6868
+
+#define AUTHTICKET_SIZE 1024
+
+#define MOTD_SIZE 512
+#define MESSAGE_SIZE 256
+
+// maximum amount of clients able to connect to a server
+#define MAX_CLIENTS 100
+
+#define PING_INTERVAL 30
+#define PING_TIMEOUT 40
+
+#define ITEM_MAXNAMELEN 64
+
+#include <boost/cstdlib.hpp>
+#include <boost/unordered_map.hpp>
+#include <fstream>
+#include <sstream>
+#include <ostream>
+#include <iostream>
+#include <iomanip>
+#include <time.h>
+
+#include "Steamworks.h"
+#include "Common.h"
+#include "NetMessages.h"
+#include "util.h"
+#include "IdlerContext.h"
+#include "FileLogger.h"
+
+#endif // COMMON_H

idler2/FileLogger.cpp

+
+#include "FileLogger.h"
+
+CFileLogger::CFileLogger( const char *fName )
+{
+	m_fName = new char[ 260 ];
+	_strcpy_s( m_fName, 260, fName );
+}
+
+CFileLogger::~CFileLogger()
+{
+	delete [] m_fName;
+}
+
+
+void CFileLogger::Log( const char *msg )
+{
+	FILE *hFile = fopen( m_fName, "a" );
+	if ( !hFile )
+		return;
+
+	fwrite( msg, 1, strlen( msg ), hFile );
+
+	fclose( hFile );
+}

idler2/FileLogger.h

+#ifndef FILELOGGER_H
+#define FILELOGGER_H
+
+#include "Common.h"
+
+class CFileLogger
+{
+
+public:
+	CFileLogger( const char *fName );
+	~CFileLogger();
+
+	void Log( const char *msg );
+
+private:
+	char *m_fName;
+
+};
+
+
+#endif

idler2/IdlerContext.h

+#ifndef IDLERCONTEXT_H
+#define IDLERCONTEXT_H
+
+#include "Common.h"
+
+class IdlerContext
+{
+public:
+	IdlerContext(ISteamClient008 *steam_client) : client(steam_client), pipe(0), user(0), running(false) {}; 
+	virtual bool Begin() = 0;
+	virtual void End() = 0;
+	virtual void Think() = 0;
+	virtual void HandleCallback(const CallbackMsg_t &callback) = 0;
+
+	virtual bool IsRunning() { return running; };
+	virtual HSteamPipe GetPipe() { return pipe; };
+
+protected:
+	ISteamClient008 *client;
+
+	HSteamPipe pipe;
+	HSteamUser user;
+
+	bool running;
+};
+
+
+#endif //IDLERCONTEXT_H

idler2/Makefile.linux_makefile

+CC=gcc
+CFLAGS=-m32 -c -Wall -I"../Open Steamworks" -I"../boost_1_40_0" -Wfatal-errors
+LDFLAGS=-m32 -lstdc++ -Wl,-R./ -L./ steamclient_linux.so
+SOURCES=main.cpp util.cpp CItemDB.cpp FileLogger.cpp CUser.cpp CClientContext.cpp CServerContext.cpp
+OBJECTS=$(SOURCES:.cpp=.o)
+EXECUTABLE=idler2
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS) 
+	$(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.cpp.o:
+	$(CC) $(CFLAGS) $< -o $@

idler2/NetMessages.h

+#ifndef NETMESSAGES_H
+#define NETMESSAGES_H
+
+enum ENetworkMessage
+{
+	// server
+	eServerBegin = 0,
+	eServerConnectionDenied = eServerBegin + 1,
+	eServerSendInfo = eServerBegin + 2,
+	eServerClientAuthed = eServerBegin + 3,
+	eServerPingRequest = eServerBegin + 4,
+	eServerClientKicked = eServerBegin + 5,
+	eServerYourItemWas = eServerBegin + 6,
+
+	// client
+	eClientBegin = 1000,
+	eClientInitConnection = eClientBegin + 1,
+	eClientAuth = eClientBegin + 2,
+	eClientPingReply = eClientBegin + 3,
+	eClientItemGranted = eClientBegin + 4,
+
+	eWORD = 0xFFFFFF,
+
+};
+
+enum EConnectionDenyReason
+{
+	EDenyServerFull,
+	EDenyAuthFailed,
+	EDenySteamIDBanned,
+	EDenySteamIDExists,
+	
+	EDenyClientOutdated,
+
+	eBYTE = 0xFF,
+};
+
+
+struct NetMessageBase_t
+{
+	NetMessageBase_t(ENetworkMessage mt) : messageType(mt) {};
+
+	const ENetworkMessage messageType;
+};
+
+struct NetServerConnectionDenied_t : NetMessageBase_t
+{
+	NetServerConnectionDenied_t() : NetMessageBase_t( eServerConnectionDenied ) { }
+
+	EConnectionDenyReason denyReason;
+	char optionalMessage[ MESSAGE_SIZE ];
+};
+
+#pragma pack(push, 1)
+struct NetServerSendInfo_t : NetMessageBase_t
+{
+	NetServerSendInfo_t() : NetMessageBase_t( eServerSendInfo) {}
+
+	CSteamID serverSteamID;
+	bool vacSecure;
+};
+#pragma pack(pop)
+
+struct NetServerClientAuthed_t : NetMessageBase_t
+{
+	NetServerClientAuthed_t() : NetMessageBase_t( eServerClientAuthed ) { }
+
+	char messageOfTheDay[ MOTD_SIZE ];
+	// maybe send other last details to an authed client?
+};
+
+struct NetServerPingRequest_t : NetMessageBase_t
+{
+	NetServerPingRequest_t() : NetMessageBase_t( eServerPingRequest ) { }
+
+	uint32 itemsTotal;
+};
+
+struct NetServerClientKicked_t : NetMessageBase_t
+{
+	NetServerClientKicked_t() : NetMessageBase_t( eServerClientKicked ) { }
+
+	char kickMessage[ MESSAGE_SIZE ];
+};
+
+struct NetServerYourItemWas_t : NetMessageBase_t
+{
+	NetServerYourItemWas_t() : NetMessageBase_t( eServerYourItemWas ) { };
+
+	char itemName[ITEM_MAXNAMELEN];
+};
+
+struct NetClientInitConnection_t : NetMessageBase_t
+{
+	NetClientInitConnection_t() : NetMessageBase_t( eClientInitConnection ) { }
+
+	uint32 clientProtocolVersion;
+};
+
+struct NetClientAuth_t : NetMessageBase_t
+{
+	NetClientAuth_t() : NetMessageBase_t( eClientAuth ) { }
+
+	// uint64 clientSteamID; // probably located in the auth ticket
+	uint32 ticketLen;
+	byte authTicket[ AUTHTICKET_SIZE ];
+	char username[ k_cchPersonaNameMax ];
+};
+
+struct NetClientPingReply_t : NetMessageBase_t
+{
+	NetClientPingReply_t() : NetMessageBase_t( eClientPingReply ) { }
+
+};
+
+struct NetClientItemGranted_t : NetMessageBase_t
+{
+	NetClientItemGranted_t() : NetMessageBase_t( eClientItemGranted ) { }
+
+	uint32 itemid;
+};
+
+#endif // NETMESSAGES_H

idler2/client.vcproj

+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="idler2 client"
+	ProjectGUID="{BB206289-BD8F-4A7C-AF22-D64222C25F01}"
+	RootNamespace="idler2client"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../open steamworks/"
+				PreprocessorDefinitions="CLIENT"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib ../steam_api.lib ../steamclient.lib"
+				OutputFile="$(OutDir)\client.exe"
+				DelayLoadDLLs="steamclient.dll"
+				GenerateDebugInformation="true"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="../open steamworks/"
+				PreprocessorDefinitions="CLIENT"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib ../steam_api.lib ../steamclient.lib"
+				OutputFile="$(OutDir)\client.exe"
+				DelayLoadDLLs="steamclient.dll"
+				GenerateDebugInformation="true"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\Client.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\Client.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Common.h"
+				>
+			</File>
+			<File
+				RelativePath=".\NetMessages.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

idler2/idler2.sln

+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "idler2", "idler2.vcproj", "{B64830ED-AE55-42AC-BC81-979CCA5A6B59}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B64830ED-AE55-42AC-BC81-979CCA5A6B59}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B64830ED-AE55-42AC-BC81-979CCA5A6B59}.Debug|Win32.Build.0 = Debug|Win32
+		{B64830ED-AE55-42AC-BC81-979CCA5A6B59}.Release|Win32.ActiveCfg = Release|Win32
+		{B64830ED-AE55-42AC-BC81-979CCA5A6B59}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

idler2/idler2.vcproj

+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="idler2"
+	ProjectGUID="{B64830ED-AE55-42AC-BC81-979CCA5A6B59}"
+	RootNamespace="idler2"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"