summaryrefslogtreecommitdiff
path: root/gcsdk/steamextra
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /gcsdk/steamextra
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'gcsdk/steamextra')
-rw-r--r--gcsdk/steamextra/clientenums.h611
-rw-r--r--gcsdk/steamextra/gamecoordinator/igamecoordinator.h33
-rw-r--r--gcsdk/steamextra/gamecoordinator/igamecoordinatorhost.h31
-rw-r--r--gcsdk/steamextra/gamecoordinator/igcsqlquery.h67
-rw-r--r--gcsdk/steamextra/gamecoordinator/igcsqlresultsetlist.h62
-rw-r--r--gcsdk/steamextra/misc.cpp187
-rw-r--r--gcsdk/steamextra/misc.h121
-rw-r--r--gcsdk/steamextra/rtime.cpp1216
-rw-r--r--gcsdk/steamextra/rtime.h187
-rw-r--r--gcsdk/steamextra/steam/isteamgamecoordinator.h64
-rw-r--r--gcsdk/steamextra/steamid.cpp729
-rw-r--r--gcsdk/steamextra/tier0/t0constants.h35
-rw-r--r--gcsdk/steamextra/tier1/hashglobals.cpp35
-rw-r--r--gcsdk/steamextra/tier1/murmurhash3.cpp74
-rw-r--r--gcsdk/steamextra/tier1/murmurhash3.h100
-rw-r--r--gcsdk/steamextra/tier1/pearsonshash.h268
-rw-r--r--gcsdk/steamextra/tier1/tsmempool.cpp255
-rw-r--r--gcsdk/steamextra/tier1/tsmempool.h170
-rw-r--r--gcsdk/steamextra/tier1/tsmultimempool.cpp383
-rw-r--r--gcsdk/steamextra/tier1/tsmultimempool.h97
-rw-r--r--gcsdk/steamextra/tier1/utlhashmaplarge.h693
21 files changed, 5418 insertions, 0 deletions
diff --git a/gcsdk/steamextra/clientenums.h b/gcsdk/steamextra/clientenums.h
new file mode 100644
index 0000000..a2888d8
--- /dev/null
+++ b/gcsdk/steamextra/clientenums.h
@@ -0,0 +1,611 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef CLIENTENUMS_H
+#define CLIENTENUMS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+enum ELogonState
+{
+ k_ELogonStateNotLoggedOn = 0,
+ k_ELogonStateLoggingOn = 1,
+ k_ELogonStateLoggingOff = 2,
+ k_ELogonStateLoggedOn = 3
+};
+
+
+// Enums for all personal questions supported by the system.
+enum EPersonalQuestion
+{
+ // Never ever change these after initial release.
+ k_EPSMsgNameOfSchool = 0, // Question: What is the name of your school?
+ k_EPSMsgFavoriteTeam = 1, // Question: What is your favorite team?
+ k_EPSMsgMothersName = 2, // Question: What is your mother's maiden name?
+ k_EPSMsgNameOfPet = 3, // Question: What is the name of your pet?
+ k_EPSMsgChildhoodHero = 4, // Question: Who was your childhood hero?
+ k_EPSMsgCityBornIn = 5, // Question: What city were you born in?
+
+ k_EPSMaxPersonalQuestion
+};
+
+
+// account flags (stored in DB)
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASEd
+enum EAccountFlags
+{
+ m_EAccountFlagNormalUser = 0, // Standard user level (yes, this is meant to be zero)
+ k_EAccountFlagPersonaNameSet = ( 1 << 0 ), // true if the user has set the persona name they really want, instead of the auto-generated one
+ k_EAccountFlagUnbannable = ( 1 << 1 ), // whatever happens, this account can't be banned
+ k_EAccountFlagPasswordSet = ( 1 << 2 ), // we've set the password at least once on this account
+ k_EAccountFlagSupport = ( 1 << 3 ), // Enables use of web support tool
+ k_EAccountFlagAdmin = ( 1 << 4 ), // The name says it all, can do everything
+ k_EAccountFlagSupervisor = ( 1 << 5 ), // support supervisory role
+ k_EAccountFlagAppEditor = ( 1 << 6 ), // Can edit app info
+ k_EAccountFlagHWIDSet = ( 1 << 7 ), // Set HWID once
+ k_EAccountFlagPersonalQASet = ( 1 << 8 ), // user has personal Question & anser set
+ k_EAccountFlagVacBeta = ( 1 << 9 ), // user participates in VAC beta tests
+ k_EAccountFlagDebug = ( 1 << 10 ), // user is in debug mode, eg VAC doesn't kick etc
+ k_EAccountFlagDisabled = ( 1 << 11 ), // account is disabled.
+ k_EAccountFlagLimitedUser = ( 1 << 12 ), // account is limited user account because it doesnt own anything
+ k_EAccountFlagLimitedUserForce = ( 1 << 13 ), // account is limited user account because we forced it to be
+ k_EAccountFlagEmailValidated = ( 1 << 14 ), // user has verified email address via WG
+ k_EAccountFlagMarketingTreatment = ( 1 << 15), // account is flagged as being in a treatment for marketing/sales experiments
+};
+
+// profile state (stored in DB)
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ECommunityProfileState
+{
+ k_ECommunityProfileNotCreated = 0, // user hasn't setup community account yet
+ k_ECommunityProfileActive = 1, // user joined community, site is public
+ k_ECommunityProfilePrivate = 2, // user joined community, site is private
+ k_ECommunityProfileLocked = 3, // user got locked, content can't be changed but is still accessible
+ k_ECommunityProfileDisabled = 4, // user got disabled, site not accessible anymore
+};
+
+
+// profile privacy option setting (stored in DB)
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ECommunityPrivacyState
+{
+ k_ECommunityPrivacyInvalid = 0,
+ k_ECommunityPrivacyPrivate = 1, // ain't nobody can see it
+ k_ECommunityPrivacyFriendsOnly = 2, // only your friends can see it
+ k_ECommunityPrivacyPublic = 3, // anybody could see it
+};
+
+enum ECommunityVisibilityState
+{
+ k_ECommunityVisibilityPrivate = 1, // private, requester see only public fields
+ k_ECommunityVisibilityFriendsOnly = 2, // friends only, requester sees only public fields
+ k_ECommunityVisibilityOpen = 3, // it is visible to requester; they are owner or friend or public
+ k_ECommunityVisibilitySupportPrivate = 4, // was private, but it's a support account asking
+ k_ECommunityVisibilitySupportFriendsOnly = 5,// was friends only, but it's a support account asking
+};
+
+enum ECommentPermission
+{
+ k_ECommentPermissionFriendsOnly = 0, // only friends can leave a comment
+ k_ECommentPermissionAnyone = 1, // anybody can leave a comment
+ k_ECommentPermissionSelfOnly = 2, // only the account owner can leave a comment
+};
+
+// Payment methods for purchases - BIT FLAGS so can be used to indicate
+// acceptable payment methods for packages
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum EPaymentMethod
+{
+ k_EPaymentMethodNone = 0x000, // user got the license for free
+ k_EPaymentMethodActivationCode = 0x001, // user paid by entering unused CD-Key or other activation code
+ k_EPaymentMethodCreditCard = 0x002, // user paid with credit card
+ k_EPaymentMethodPayPal = 0x004, // user paid with via paypal
+ k_EPaymentMethodGuestPass = 0x008, // user paid by redeeming a guest pass
+ k_EPaymentMethodHardwarePromo = 0x010, // user presented machine credentials
+ k_EPaymentMethodClickAndBuy = 0x020, // ClickandBuy
+ k_EPaymentMethodAutoGrant = 0x040, // server side purchased package, things like German specific TF2 free weekend
+ k_EPaymentMethodWallet = 0x080, // user paid with wallet
+ k_EPaymentMethodOEMTicket = 0x100, // user paid by redeeming a OEM license ticket
+ k_EPaymentMethodSplit = 0x200, // user paid with wallet AND a provider
+};
+
+// Sources for WalletTxn records
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum EWalletSource
+{
+ k_EWalletSourceInvalid = 0,
+ k_EWalletSourcePurchase = 1, // Created from a purchase, refund, chargeback, or reverse chargeback (PurchaseRefGID -> TransID)
+ k_EWalletSourceGuestPass = 2, // Created from a guest pass (PurchaseRefGID -> GuestPassID)
+ k_EWalletSourceConversion = 3, // Created from a wallet conversion (PurchaseRefGID -> GID shared between debit & credit records)
+ k_EWalletSourceRebate = 4, // Created from a rebate (PurchaseRefGID -> TransID)
+};
+
+// License types
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ELicenseType
+{
+ k_ENoLicense = 0, // for shipped goods
+ k_ESinglePurchase = 1, // single purchase
+ k_ESinglePurchaseLimitedUse = 2, // single purchase w/ expiration
+ k_ERecurringCharge = 3, // recurring subscription
+ k_ERecurringChargeLimitedUse = 4, // recurring subscription w/ limited minutes per period
+ k_ERecurringChargeLimitedUseWithOverages = 5, // like above but w/ soft limit and overage charges
+};
+
+// Flags for licenses - BITS
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ELicenseFlags
+{
+ k_ELicenseFlagNone = 0x00, // just a place holder
+ k_ELicenseFlagRenew = 0x01, // Renew this license next period
+ k_ELicenseFlagRenewalFailed = 0x02, // Auto-renew failed
+ k_ELicenseFlagPending = 0x04, // Purchase or renewal is pending
+ k_ELicenseFlagExpired = 0x08, // Set if no longer active (whatever the reason)
+ k_ELicenseFlagCancelledByUser = 0x10, // Cancelled by the user
+ k_ELicenseFlagCancelledByAdmin = 0x20, // Cancelled by customer support
+ k_ELicenseFlagLowViolenceContent = 0x40,// license is for low violence content
+};
+
+// Status of a package
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum EPackageStatus
+{
+ k_EPackageAvailable = 0, // Available for purchase and use
+ k_EPackagePreorder = 1, // Available for purchase, as a pre-order
+ k_EPackageUnavailable = 2, // Not available for new purchases, may still be owned
+ k_EPackageInvalid = 3, // Either an unknown package or a deleted one that nobody should own
+};
+
+// Purchase status
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum EPurchaseStatus
+{
+ k_EPurchasePending = 0, // purchase is pending, valid but pending subscription
+ k_EPurchaseSucceeded = 1, // purchase successful, valid subscription
+ k_EPurchaseFailed = 2, // purchase failed, no subscription
+ k_EPurchaseRefunded = 3, // we refunded the purchase and removed subscription
+ k_EPurchaseInit = 4, // user started purchase
+ k_EPurchaseChargedback = 5, // the user issued a chargeback, we removed subscription
+ k_EPurchaseRevoked = 6, // we revoked the purchase and removed subscription. Usually stolen CD-Keys
+ k_EPurchaseInDispute = 7, // the purchase is being disputed by the user, preliminary to a chargeback
+};
+
+// LineItemTypes
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASEd
+enum ELineItemType
+{
+ k_ELineItemTypeInvalid = 0, // Unknown - load all purchase line items
+ k_ELineItemTypeMicroTxn = ( 1 << 0 ), // Transaction has data in MicroTxnLineItem table
+ k_ELineItemTypeWallet = ( 1 << 1 ), // Transaction has data in WalletLineItem table
+ k_ELineItemTypePkg = ( 1 << 2 ), // Transaction has data in PurchaseLineItem table
+};
+
+// Enum for the types of news push items you can get
+enum ENewsUpdateType
+{
+ k_EAppNews = 0, // news about a particular app
+ k_ESteamAds = 1, // Marketing messages
+ k_ESteamNews = 2, // EJ's corner and the like
+ k_ECDDBUpdate = 3, // backend has a new CDDB for you to load
+ k_EClientUpdate = 4, // new version of the steam client is available
+};
+
+// Detailed purchase result codes for the client
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum EPurchaseResultDetail
+{
+ k_EPurchaseResultNoDetail = 0,
+ k_EPurchaseResultAVSFailure = 1,
+ k_EPurchaseResultInsufficientFunds = 2,
+ k_EPurchaseResultContactSupport = 3,
+ k_EPurchaseResultTimeout = 4,
+
+ k_EPurchaseResultInvalidPackage = 5,
+ k_EPurchaseResultInvalidPaymentMethod = 6,
+ k_EPurchaseResultInvalidData = 7,
+ k_EPurchaseResultOthersInProgress = 8,
+ k_EPurchaseResultAlreadyPurchased = 9,
+ k_EPurchaseResultWrongPrice = 10,
+ k_EPurchaseResultFraudCheckFailed = 11,
+ k_EPurchaseResultCancelledByUser = 12,
+ k_EPurchaseResultRestrictedCountry = 13,
+ k_EPurchaseResultBadActivationCode = 14, // this code gives no receipt
+ k_EPurchaseResultDuplicateActivationCode = 15,
+
+ k_EPurchaseResultUseOtherPaymentMethod = 16, // User should try a different payment method
+ k_EPurchaseResultUseOtherFundingSource = 17, // Select a different funding source (paypal)
+ k_EPurchaseResultInvalidShippingAddress = 18, // Shipping address is invalid (paypal)
+ k_EPurchaseResultRegionNotSupported = 19, // This region is not supported with this payment type
+
+ k_EPurchaseResultAcctIsBlocked = 20, // Acct has been blocked by provider - user should contact provider to resolve
+ k_EPurchaseResultAcctNotVerified = 21, // Provider indicated account needs to be verified for transaction to complete
+
+ k_EPurchaseResultInvalidAccount = 22, // Provider indicated the account is invalid or no longer usable
+ k_EPurchaseResultStoreBillingCountryMismatch = 23, // store country code & billing country code do not match
+ k_EPurchaseResultDoesNotOwnRequiredApp = 24, // user does not own one of the apps required for purchase
+ k_EPurchaseResultCanceledByNewTransaction = 25, // user made a new transaction which canceled an old, pending transaction
+ k_EPurchaseResultForceCanceledPending = 26, // A pending transaction was force canceled (no response from provider)
+ k_EPurchaseResultFailCurrencyTransProvider = 27, // selected transaction provider does not support calculated currency
+ k_EPurchaseResultFailedCyberCafe = 28, // cybercafe account tried to purchase or use an activation code
+
+ k_EPurchaseResultNeedsPreApproval = 29, // Transaction needs approval from support
+ k_EPurchaseResultPreApprovalDenied = 30, // Transaction was denied by support
+ k_EPurchaseResultWalletCurrencyMismatch = 31, // Currency of purchase does not match currency of wallet
+};
+
+// Type of system IM. The client can use this to do special UI handling in specific circumstances
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ESystemIMType
+{
+ k_ESystemIMRawText = 0,
+ k_ESystemIMInvalidCard = 1,
+ k_ESystemIMRecurringPurchaseFailed = 2,
+ k_ESystemIMCardWillExpire = 3,
+ k_ESystemIMSubscriptionExpired = 4,
+ k_ESystemIMGuestPassReceived = 5, // User has received a guest pass from a friend
+ k_ESystemIMGuestPassGranted = 6, // System has granted a user a guest pass to give out
+ k_ESystemIMGiftRevoked = 7, // We revoked a gift due to chargeback, etc
+
+ //
+ k_ESystemIMTypeMax
+};
+
+// Ways an external cd key can be munged onto a users PC
+enum ELegacyKeyRegistrationMethod
+{
+ eLegacyKeyRegistrationMethodNone = 0, // doesn't support legacy cd keys
+ eLegacyKeyRegistrationMethodRegistry, // just place it into the registry
+ eLegacyKeyRegistrationMethodDisk, // put it in a file on disk
+};
+
+// Support events, generated by system or support input
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ESupportEvent
+{
+ // support activity
+ eSupportNote = 0, // a generic support note
+ eSupportLogin = 1, // support account logged in out, data: IP:Port
+ eSupportLogoff = 2, // support account logged out, text: IP:Port
+ eSupportTicketCreated = 3, // a support ticket was created
+ eSupportTicketClosed = 4, // problem was solved, ticket closed
+
+ // account changes
+ eSupportEnableAccount = 5, // support enabled account, text: reason
+ eSupportDisableAccount = 6, // support disabled account, text: reason
+ eSupportChangeAccountPassword = 7, // support or user changed password, data: DONT include old password
+ eSupportChangeAccountEmail = 8, // support or user changed email, data: old email
+ eSupportChangeAccountName = 9, // support or user changed name, data: old name
+ eSupportChangeAccountPlayer = 10, // support or user changed player name, data: old name
+
+ eSupportPurchaseChargedback = 11, // a charge back was issued
+ eSupportPurchaseRefunded = 12, // a refund was issued
+ eSupportPurchaseForcedCompletion = 13, // support forced a pending purchase to complete
+
+ // license handling
+ eSupportLicenseAdded = 14, // support added a license, text: reason
+ eSupportLicenseCanceled = 15, // support or user cancel a license
+ eSupportLicenseChanged = 16, // support removed a license, text: reason
+ eSupportBannedGame = 17, // support banned game for an account
+ eSupportUnbannedGame = 18, // support unbanned game for an account
+
+ // purchase activity
+ eSupportRunPurchase = 19,
+ eSupportChangedCreditCard = 20, // support updated a credit card
+ eSupportSetNoFraudCheckFlag = 21, // support disabled fraud check, data: reason
+
+ // banning
+ eSupportBannedCreditCard = 22, // support banned a credit card
+ eSupportBannedIP = 23, // support banned an IP
+ eSupportBannedCDKey = 24, // support banned an CDKey
+ eSupportBannedCountry = 25, // support banned a country
+ eSupportBannedPayPalAccount = 26,
+
+ eSupportPurchaseCanceled = 27, // support forced a pending purchase to cancel
+
+ eSupportChangeAvatar = 28,
+ eSupportChangeProfileURL = 29,
+
+ eSupportRegisterCDKey = 30, // support added a CD key to this account
+ eSupportGrantGuestPass = 31, // support granted a guest pass to this account
+ eSupportResubmitTransaction = 32, // support resubmitted a transaction
+
+ eSupportResetContent = 33, // reset user content based on abuse reports
+ eSupportLockProfile = 34, // temp block a user from modifying community content
+ eSupportSetCommunityState = 35, // perm lock a user profile, can't be modified
+ eSupportDeleteAbuseReports = 36, // deleted abuse reports for the SteamID
+ eSupportSetAccountFlags = 37, // changed account flags
+
+ eSupportChargebackStatusUpdate = 38, // support updated the pending chargeback status
+
+ eSupportRefundForcedCompletion = 39, // support forced a pending refund to complete
+ eSupportRefundCanceled = 40, // support forced a pending refund to cancel
+
+ eSupportRevokeActivationKey = 41, // support revoked and unlocked activation key
+ eSupportReverseChargeback = 42, // a charge back was reversed
+ eSupportRejectedActivationKey = 43, // activation key was rejected (invalid or already used)
+
+ eSupportPurchaseError = 44, // Purchase error
+ eSupportAudited = 45,
+
+ // items
+ eSupportBanItems = 46, // support banned a user's items
+ eSupportRestoreBannedItems = 47, // support restored banned items
+ eSupportRestoreDeletedItems = 48, // support restored deleted items
+
+ // comments
+ eSupportDeleteComments = 49, // cleared comments on this account (not written by this account)
+
+ eSupportDeleteItems = 50, // support deleted a user's items
+ eSupportDeleteCachedCard = 51, // support deleted a user's cached credit card
+
+ eSupportConvertedWallet = 52, // user's wallet was converted
+
+ eSupportTxnApproved = 53, // PreApproval granted
+ eSupportTxnDenied = 54, // PreApproval denied
+
+ eSupportGCAction = 55, // used for all support actions from the GC
+};
+
+
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ESupportTicket
+{
+ // all kinds of problems tickets that have to be handled by support
+ k_ETicketUnknown = 0, // an unknown problem. yay.
+ k_ETicketManual = 1, // a problem manually entered by support.
+ k_ETicketFraudRedFlag = 2, // fraud detection marked this account
+ k_ETicketPurchaseError = 3, // a purchase error happened
+ k_ETicketChargeback = 4, // a chargeback needs attention
+};
+
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ESupportTicketState
+{
+ // all kinds of problems tickets that have to be handled by support
+ k_ETicketStateUnknown = 0, // support issue state is unknown
+ k_ETicketStateUnassigned = 1, // support issue is 'open' but not assigned yet
+ k_ETicketStateInProcess = 2, // support issue is assigned to an support actor
+ k_ETicketStateResolved = 3, // support issue is fixed and closed
+ k_ETicketStateUnresolved = 4, // support issue couldn't be fixed. closed anyway
+ k_ETicketStateAutoClosed = 5, // System closed the ticket automatically
+};
+
+
+//-----------------------------------------------------------------------------
+// types of content that can be reported as abused
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+//-----------------------------------------------------------------------------
+enum ECommunityContentType
+{
+ k_EContentUnspecified = 0,
+ k_EContentAll = 1, // reset all community content
+ k_EContentAvatarImage = 2, // clear avatar image
+ k_EContentProfileText = 3, // reset profile text
+ k_EContentWebLinks = 4, // delete web links
+ k_EContentAnnouncement = 5,
+ k_EContentEventText = 6,
+ k_EContentCustomCSS = 7,
+ k_EContentProfileURL = 8, // delete community URL ID
+ k_EContentComments = 9, // just comments this guy has written
+};
+
+
+//-----------------------------------------------------------------------------
+// types of reasons why a violation report was issued
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+//-----------------------------------------------------------------------------
+enum EAbuseReportType
+{
+ k_EAbuseUnspecified = 0,
+ k_EAbuseInappropriate = 1, // just not ok to post
+ k_EAbuseProhibited = 2, // prohibited by EULA or general law
+ k_EAbuseSpamming = 3, // excessive spamming
+ k_EAbuseAdvertisement = 4, // unwanted advertisement
+ k_EAbuseExploit = 5, // content data attempts to exploit code issue
+ k_EAbuseSpoofing = 6, // user/group is impersonating an official contact
+ k_EAbuseLanguage = 7, // bad language
+ k_EAbuseAdultContent = 8, // any kind of adult material, references etc
+ k_EAbuseHarassment = 9, // harassment, discrimination, racism etc
+};
+
+//-----------------------------------------------------------------------------
+// actions for a user within a clan for logging in the ClanHistory table
+//-----------------------------------------------------------------------------
+
+enum EClanAction
+{
+ k_EJoined = 1, // joined the clan
+ k_ELeft = 2, // left the clan
+ k_EPromoted = 3, // promoted to officer
+ k_EDemoted = 4, // demoted from officer
+ k_EKicked = 5, // kicked off the clan
+ k_ECreated = 6, // clan was created
+ k_EInvited = 7, // invited someone
+ k_EEventCreated = 8, // clan event created
+ k_EEventUpdated = 9, // clan event updated
+ k_EEventDeleted = 10, // clan event deleted
+ k_EPermissionsChanged = 11, // clan permissions were changed
+ k_EAnnouncementCreated = 12, // clan announcement created
+ k_EAnnouncementUpdated = 13, // clan announcement updated
+ k_EAnnouncementDeleted = 14, // clan announcement deleted
+ k_EPOTWChanged = 15, // changed the POTW
+ k_ELinksChanged = 16, // links changed
+ k_EDetailsChanged = 17, // details changed
+ k_ESupportResetContent = 18, // support reset some or all of the clan content
+ k_ESupportLockedGroup = 19, // support locked this clan, it can't be modified anymore
+ k_ESupportUnlockedGroup = 20, // support unlocked this clan
+ k_ESupportChangedOwner = 21, // support transfered ownership
+ k_EMadePublic = 22, // made from private into public
+ k_EMadePrivate = 23, // made from public into private
+ k_ESupportDisabledGroup = 24, // support disabled this group, nobody can see it anymore
+ k_EKickedChat = 25, // kicked from chat
+ k_EBannedChat = 26, // banned from chat
+ k_EUnBannedChat = 27, // un-banned from chat
+
+ k_EHighestValidAction // keep me updated, please!
+};
+
+
+//-----------------------------------------------------------------------------
+// types of events for use in the Clan Event Type table
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+//-----------------------------------------------------------------------------
+enum EClanEventType
+{
+ k_EOtherEvent = 1,
+ k_EGameEvent = 2,
+ k_EPartyEvent = 3,
+ k_EMeetingEvent = 4,
+ k_ESpecialCauseEvent = 5,
+ k_EMusicAndArtsEvent = 6,
+ k_ESportsEvent = 7,
+ k_ETripEvent = 8,
+ k_EChatEvent = 9,
+ k_EGameReleaseEvent = 10,
+};
+
+//-----------------------------------------------------------------------------
+// types of marketing messages displayed to users
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+//-----------------------------------------------------------------------------
+enum EMarketingMessageType
+{
+ k_EMarketingMessageNowAvailable = 1,
+ k_EMarketingMessageWeekendDeal = 2,
+ k_EMarketingMessagePrePurchase = 3,
+ k_EMarketingMessagePlayNow = 4,
+ k_EMarketingMessagePreloadNow = 5,
+ k_EMarketingMessageGeneral = 6,
+ k_EMarketingMessageDemoQuit = 7,
+ k_EMarketingMessageGifting = 8,
+ k_EMarketingMessageEJsKorner = 9,
+};
+
+//-----------------------------------------------------------------------------
+// types of associations a marketing message may have
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+//-----------------------------------------------------------------------------
+enum EMarketingMessageAssociationType
+{
+ k_EMarketingMessageNoAssociation = 0,
+ k_EMarketingMessageAppAssociation = 1,
+ k_EMarketingMessageSubscriptionAssociation = 2,
+ k_EMarketingMessagePublisherAssociation = 3,
+ k_EMarketingMessageGenreAssociation = 4,
+};
+
+//-----------------------------------------------------------------------------
+// Marketing message visibility
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+//-----------------------------------------------------------------------------
+enum EMarketingMessageVisibility
+{
+ k_EMarketingMessageVisibleBeta = 1,
+ k_EMarketingMessageVisiblePublic = 2,
+};
+
+//-----------------------------------------------------------------------------
+// Structures used in multiple messages
+//-----------------------------------------------------------------------------
+// Purchase message constants
+// WARNING: Do not change these if an instance of this record may exist in a database!!!
+// BUGBUG derrick - Since these also define schema, they should be moved into steamschema.h
+const int k_cchCCNumMax = 16 + 1;
+const int k_cchHolderNameMax = 100 + 1;
+const int k_cchExpYearMax = 4 + 1;
+const int k_cchExpMonthMax = 2 + 1;
+const int k_cchCVV2Max = 4 + 1;
+const int k_cchAddressMax = 128 + 1;
+const int k_cchAddress2Max = k_cchAddressMax;
+const int k_cchCityMax = 50 + 1;
+const int k_cchPostcodeMax = 16 + 1;
+const int k_cchStateMax = 32 + 1;
+const int k_cchPhoneMax = 20 + 1;
+const int k_cchEmailMax = 100 + 1;
+const int k_cchCountryCodeMax = 2 + 1;
+const int k_cchPayPalCheckoutTokenMax = 20 + 1;
+const int k_cchStateCodeMax = 3 + 1;
+const int k_cchCurrencyCodeMax = 3 + 1;
+
+const int k_cubMaxDfsURL = 128; // Max size for URL descriptors on DFS
+
+
+// License information
+struct LicenseInfo_t
+{
+ PackageId_t m_unPackageID;
+ RTime32 m_RTime32Created;
+ RTime32 m_RTime32NextProcess;
+ int32 m_nMinuteLimit;
+ int32 m_nMinutesUsed;
+ EPaymentMethod m_ePaymentMethod;
+ uint32 m_nFlags;
+ char m_rgchPurchaseCountryCode[k_cchCountryCodeMax];
+ int32 m_nTerritoryCode;
+};
+
+// Supported Currency Codes
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ECurrencyCode
+{
+ k_ECurrencyCodeInvalid = 0,
+ k_ECurrencyCodeUSD = 1,
+ k_ECurrencyCodeGBP = 2,
+ k_ECurrencyCodeEUR = 3,
+
+ k_ECurrencyCodeMax = 4
+};
+
+enum ETaxType
+{
+ k_ETaxTypeInvalid = 0,
+ k_ETaxTypeUSState = 1,
+ k_ETaxTypeVAT = 2
+};
+
+// client stat list
+// needs to be kept in the same order, since it's part of the protocol
+enum EClientStat
+{
+ k_EClientStatP2PConnectionsUDP = 0,
+ k_EClientStatP2PConnectionsRelay = 1,
+ k_EClientStatP2PGameConnections = 2,
+ k_EClientStatP2PVoiceConnections = 3,
+
+ k_EClientStatBytesDownloaded = 4,
+
+ k_EClientStatMax, // must be last, used as array's of data
+};
+
+enum EP2PState
+{
+ k_EP2PStateNotConnected,
+ k_EP2PStateUDP,
+ k_EP2PStateRelay,
+};
+
+// User response for authentication request
+enum EMicroTxnAuthResponse
+{
+ k_EMicroTxnAuthResponseInvalid = 0, // Invalid value
+ k_EMicroTxnAuthResponseAuthorize = 1, // user accepted microtransaction
+ k_EMicroTxnAuthResponseDeny = 2, // user denied microtransaction
+ k_EMicroTxnAuthResponseAutoDeny = 3, // client automatically denied microtransaction (user wasn't in game, etc.)
+};
+
+// Result of authorization request, returned to client
+enum EMicroTxnAuthResult
+{
+ k_EMicroTxnAuthResultInvalid = 0, // Invalid value
+ k_EMicroTxnAuthResultOK = 1, // Successfully authorized
+ k_EMicroTxnAuthResultFail = 2, // An error occurred
+ k_EMicroTxnAuthResultInsufficientFunds = 3, // User has insufficient funds to complete microtransaction
+};
+
+#endif
diff --git a/gcsdk/steamextra/gamecoordinator/igamecoordinator.h b/gcsdk/steamextra/gamecoordinator/igamecoordinator.h
new file mode 100644
index 0000000..80eb7a4
--- /dev/null
+++ b/gcsdk/steamextra/gamecoordinator/igamecoordinator.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef IGAMECOORDINATOR_H
+#define IGAMECOORDINATOR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+typedef uint32 AppId_t;
+class CSteamID;
+class IGameCoordinatorHost;
+class IGCSQLResultSetList;
+
+class IGameCoordinator
+{
+public:
+ virtual bool BInit( AppId_t unAppID, const char *pchAppPath, IGameCoordinatorHost *pHost ) = 0;
+ virtual bool BMainLoopOncePerFrame( uint64 ulLimitMicroseconds ) = 0;
+ virtual bool BMainLoopUntilFrameCompletion( uint64 ulLimitMicroseconds ) = 0;
+ virtual void Shutdown() = 0;
+ virtual void Uninit() = 0;
+ virtual void MessageFromClient( const CSteamID & senderID, uint32 unMsgType, void *pubData, uint32 cubData ) = 0;
+ virtual void Validate( CValidator &validator, const char *pchName ) = 0;
+ virtual void SQLResults( GID_t gidContextID ) = 0;
+};
+
+#define GAMECOORDINATOR_INTERFACE_VERSION "GAMECOORDINATOR003"
+
+#endif // IGAMECOORDINATOR_H
diff --git a/gcsdk/steamextra/gamecoordinator/igamecoordinatorhost.h b/gcsdk/steamextra/gamecoordinator/igamecoordinatorhost.h
new file mode 100644
index 0000000..d94f306
--- /dev/null
+++ b/gcsdk/steamextra/gamecoordinator/igamecoordinatorhost.h
@@ -0,0 +1,31 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Provides an interface that the server hosting a GC must implement
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef IGAMECOORDINATORHOST_H
+#define IGAMECOORDINATORHOST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CSteamID;
+class IGCSQLQuery;
+
+class IGameCoordinatorHost
+{
+public:
+ virtual bool BSendMessageToClient( AppId_t unAppID, const CSteamID & steamIDTarget, uint32 unMsgType, const void *pubData, uint32 cubData ) = 0;
+ virtual GID_t GenerateGID() = 0;
+ virtual void EmitMessage( const char *pchGroupName, SpewType_t spewType, int iSpewLevel, int iLevelLog, const char *pchMsg ) = 0;
+ virtual void SQLQuery( GID_t gidContextID, IGCSQLQuery *pQuery, int eSchemaCatalog ) = 0;
+ virtual void StartupComplete( bool bSuccess ) = 0;
+ virtual void ShutdownComplete() = 0;
+ virtual EUniverse GetUniverse() = 0;
+};
+
+#define GAMECOORDINATORHOST_INTERFACE_VERSION "GAMECOORDINATORHOST002"
+
+#endif // IGAMECOORDINATORHOST_H
diff --git a/gcsdk/steamextra/gamecoordinator/igcsqlquery.h b/gcsdk/steamextra/gamecoordinator/igcsqlquery.h
new file mode 100644
index 0000000..cdfd3ad
--- /dev/null
+++ b/gcsdk/steamextra/gamecoordinator/igcsqlquery.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef IGCSQLQUERY_H
+#define IGCSQLQUERY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// the type of the parameter
+enum EGCSQLType
+{
+ k_EGCSQLTypeInvalid = -1,
+
+ // Variable length types
+ k_EGCSQLType_Blob,
+ k_EGCSQLType_String,
+
+ // fixed length types
+ k_EGCSQLType_int8, // also uint8
+ k_EGCSQLType_int16, // also uint16
+ k_EGCSQLType_int32, // also uint32
+ k_EGCSQLType_int64, // also uint64
+ k_EGCSQLType_float,
+ k_EGCSQLType_double,
+ k_EGCSQLType_Binary, // raw binary data of fixed size (i.e. a C struct).
+ k_EGCSQLType_Image,
+ k_EGCSQLType_bool,
+};
+
+class IGCSQLResultSetList;
+
+class IGCSQLQuery
+{
+protected:
+ // call Destroy() instead of deleting this object directly
+ virtual ~IGCSQLQuery() {}
+
+public:
+ // returns the number of statements in the transaction
+ // represented by this query object
+ virtual uint32 GetStatementCount() = 0;
+
+ // returns a string that represents where in the GC this
+ // query came from. Usually this is FILE_AND_LINE.
+ virtual const char *PchName() = 0;
+
+ // get the null-terminated query string itself
+ virtual const char *PchCommand( uint32 unStatement ) = 0;
+
+ // gets the parameter data
+ virtual uint32 CnParams( uint32 unStatement ) = 0;
+ virtual EGCSQLType EParamType( uint32 unStatement, uint32 uIndex ) = 0;
+ virtual byte *PubParam( uint32 unStatement, uint32 uIndex ) = 0;
+ virtual uint32 CubParam( uint32 unStatement, uint32 uIndex ) = 0;
+
+ // reports the result
+ virtual void SetResults( IGCSQLResultSetList *pResults ) = 0;
+};
+
+
+#endif // IGCSQLQUERY_H
diff --git a/gcsdk/steamextra/gamecoordinator/igcsqlresultsetlist.h b/gcsdk/steamextra/gamecoordinator/igcsqlresultsetlist.h
new file mode 100644
index 0000000..ced12f2
--- /dev/null
+++ b/gcsdk/steamextra/gamecoordinator/igcsqlresultsetlist.h
@@ -0,0 +1,62 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef IGCSQLRESULTSETLIST_H
+#define IGCSQLRESULTSETLIST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "igcsqlquery.h"
+
+enum EGCSQLError
+{
+ k_EGCSQLErrorNone = 0,
+ k_EGCSQLErrorUnknown,
+ k_EGCSQLErrorBacklog,
+ k_EGCSQLErrorBadQueryParameters,
+ k_EGCSQLErrorConnectionError,
+ k_EGCSQLErrorDataTruncated,
+ k_EGCSQLErrorDeadlockLoser,
+ k_EGCSQLErrorDuplicateKey,
+ k_EGCSQLErrorGenericError,
+ k_EGCSQLErrorNoResultSet,
+ k_EGCSQLErrorSyntaxError,
+ k_EGCSQLErrorTableOrViewNotFound,
+ k_EGCSQLErrorTimeout,
+ k_EGCSQLErrorConstraintViolation,
+ k_EGCSQLErrorNumericValueOutOfRange,
+ k_EGCSQLErrorRollbackFailed,
+ k_EGCSQLErrorColumnNotFound,
+};
+
+
+class IGCSQLResultSet
+{
+public:
+ virtual uint32 GetColumnCount() = 0;
+ virtual EGCSQLType GetColumnType( uint32 nColumn ) = 0;
+ virtual const char *GetColumnName( uint32 nColumn ) = 0;
+
+ virtual uint32 GetRowCount() = 0;
+ virtual bool GetData( uint32 unRow, uint32 unColumn, uint8 **ppData, uint32 *punSize ) = 0;
+};
+
+
+class IGCSQLResultSetList
+{
+public:
+ virtual EGCSQLError GetError() = 0;
+ virtual uint32 GetResultSetCount() = 0;
+ virtual IGCSQLResultSet *GetResultSet( uint32 nResultSetIndex ) = 0;
+ virtual uint32 GetRowsAffected( uint32 unWhichStatement ) = 0;
+ virtual void Destroy() = 0;
+ virtual const char *GetErrorText() = 0;
+};
+
+
+#endif // IGCSQLRESULTSETLIST_H
diff --git a/gcsdk/steamextra/misc.cpp b/gcsdk/steamextra/misc.cpp
new file mode 100644
index 0000000..ed3facb
--- /dev/null
+++ b/gcsdk/steamextra/misc.cpp
@@ -0,0 +1,187 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Miscellaneous code
+//
+//=============================================================================
+
+#include "stdafx.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Tells us whether an account name looks like a VTT account name
+// (used as an exception for IP-based rate limiting)
+//-----------------------------------------------------------------------------
+bool IsVTTAccountName( const char *szAccountName )
+{
+ const static char *k_szCafe = "valvecafepc";
+
+ if ( 0 == Q_strncmp( szAccountName, k_szCafe, Q_strlen( k_szCafe ) ) )
+ return true;
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Random number generation
+// Use this system for all random number generation. It's very fast, and is
+// integrated with our automated tests so that we can perform reproducibly "random"
+// test cases.
+//-----------------------------------------------------------------------------
+uint32 g_unRandCur = 0;
+int g_iunRandMask = 0;
+
+// k_rgunMask
+// Set of masks used by our quick and dirty random number generator.
+const uint32 k_rgunMask[17] =
+{
+ 0x1739a3b0,
+ 0xb8907fe1,
+ 0x8290d3b7,
+ 0x72839cd0,
+ 0x242df096,
+ 0x3829750b,
+ 0x38de7a77,
+ 0x72f0924c,
+ 0x44783927,
+ 0x01925372,
+ 0x20902714,
+ 0x27585920,
+ 0x27890632,
+ 0x82910476,
+ 0x72906721,
+ 0x28798904,
+ 0x78592700,
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Quickly generates a vaguely random number.
+// Output: A vaguely random number.
+//-----------------------------------------------------------------------------
+uint32 UNRandFast()
+{
+ g_iunRandMask++;
+ g_unRandCur += 637429601; // Just add a large prime number (we'll wrap frequently)
+ return ( g_unRandCur ^ k_rgunMask[ g_iunRandMask % 17 ] );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Quickly generates a vaguely random character.
+// Output: A vaguely random char in the range [32,126].
+//-----------------------------------------------------------------------------
+char CHRandFast()
+{
+ return ( UNRandFast() % 95 ) + 32;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the random number seed (note that we actually break this down
+// into two parts: g_unRandCur and g_iunRandMask).
+// Input: ulRandSeed: Value to use as our seed
+//-----------------------------------------------------------------------------
+void SetRandSeed( uint64 ulRandSeed )
+{
+ g_unRandCur = ulRandSeed >> 32;
+ g_iunRandMask = ulRandSeed & 0xffffffff;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the current random number seed (actually a composite of
+// g_unRandCur and g_iunRandMask)
+// Output: Our current 64 bit random number seed.
+//-----------------------------------------------------------------------------
+uint64 GetRandSeed()
+{
+ return ( ( ((uint64)g_unRandCur) << 32 ) + g_iunRandMask );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Quickly fill a memory block with random bytes
+//-----------------------------------------------------------------------------
+void RandMem(void *dest, int count)
+{
+ unsigned char *pDest = (unsigned char *)dest;
+
+ while ( count >= 4 )
+ {
+ *(uint32*)(pDest) = UNRandFast();
+ pDest+=4;
+ count-=4;
+ }
+
+ while ( count > 0 )
+ {
+ *pDest = UNRandFast();
+ pDest++;
+ count--;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculates the percentage of numerator/demoninator, or 0 if
+// denominator is 0.
+//-----------------------------------------------------------------------------
+float SafeCalcPct( uint64 ulNumerator, uint64 ulDenominator )
+{
+ if ( 0 == ulDenominator )
+ return 0;
+ return ( 100.0f * (float) ulNumerator / (float) ulDenominator );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Common code to reject an operation due to a time backlog.
+// Does a gradual fade of 0% rejections at the specified threshold
+// up to 100% at the limit. The gradual fade reduces system oscillations
+// that could occur if you abruptly stop allowing all operations.
+// Input: nBacklogCur - the current backlog (in arbitrary units)
+// nBacklogThreshold - the threshold backlog at which to begin rejecting
+// nBacklogLimit - hard limit at which to reject 100% of operations
+// iItem - a monotonically increasing counter of items submitted. Used
+// to determine which operations are allowed if there is a partial
+// rejection rate.
+//-----------------------------------------------------------------------------
+bool BRejectDueToBacklog( int nBacklogCur, int nBacklogThreshold, int nBacklogLimit, int iItem )
+{
+ bool bRefuse = false;
+
+ if ( nBacklogCur >= nBacklogLimit )
+ {
+ // if we're over the hard backlog limit, refuse all operations
+ bRefuse = true;
+ }
+ else if ( nBacklogCur >= nBacklogThreshold )
+ {
+ // if we're near the hard backlog limit, start refusing an increasing % of operations,
+ // so we don't snap abruptly in and out of accepting operations and potentially cause oscillations
+
+ // ramp from refusing 0% of operations at the backlog threshold up to 100% at the backlog hard limit
+
+ // calculate refuse % to nearest 10%, to make it easy to mod the item # and get a good distribution
+ float nRefusePctDecile = 10 * (float) ( nBacklogCur - nBacklogThreshold ) /
+ (float) ( nBacklogLimit - nBacklogThreshold );
+ Assert( nRefusePctDecile >= 0.0 );
+ Assert( nRefusePctDecile <= 10.0 );
+
+ // compare the operations submitted count mod 10 to the refusal percent decile to decide if we should
+ // accept or refuse this particular operation
+ if ( ( iItem % 10 ) < nRefusePctDecile )
+ bRefuse = true;
+ }
+
+ return bRefuse;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Defines the head of the CDumpMemFnReg linked list
+//-----------------------------------------------------------------------------
+CDumpMemFnReg *CDumpMemFnReg::sm_Head = NULL; \ No newline at end of file
diff --git a/gcsdk/steamextra/misc.h b/gcsdk/steamextra/misc.h
new file mode 100644
index 0000000..d1ced65
--- /dev/null
+++ b/gcsdk/steamextra/misc.h
@@ -0,0 +1,121 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Miscellaneous platform-specific code
+//
+//=============================================================================
+
+
+#ifndef MISC_H
+#define MISC_H
+
+// Random number utilities
+uint32 UNRandFast();
+char CHRandFast();
+void SetRandSeed( uint64 ulRandSeed );
+uint64 GetRandSeed();
+void RandMem(void *dest, int count);
+
+bool IsVTTAccountName( const char *szAccountName );
+
+float SafeCalcPct( uint64 ulNumerator, uint64 ulDenominator );
+
+bool BRejectDueToBacklog( int nBacklogCur, int nBacklogThreshold, int nBacklogLimit, int iItem );
+
+#define SAFE_CLOSE_HANDLE( x ) if ( INVALID_HANDLE_VALUE != ( x ) ) { CloseHandle( x ); ( x ) = INVALID_HANDLE_VALUE; }
+#define SAFE_DELETE( x ) if ( NULL != ( x ) ) { delete ( x ); ( x ) = NULL; }
+#define SAFE_CLOSE_HCONNECTION( x ) if ( 0 != ( x ) ) { CNet::BClose( ( x ) ); ( x ) = 0; }
+#define SAFE_RELEASE( x ) if ( NULL != ( x ) ) { ( x )->Release(); x = NULL; }
+
+#define DECLARE_STEAM_CLASS_SIMPLE( className, baseClassName ) \
+ typedef baseClassName BaseClass; \
+ typedef className ThisClass; \
+
+#define DECLARE_STEAM_CLASS_NOBASE( className ) \
+ typedef className ThisClass; \
+
+// Type for our memory output debugging.
+class IDisplayMemPoolStats
+{
+public:
+ virtual void Display( const char *pszClassName, uint64 ulClassSize, uint32 unPoolInstanceCount, uint64 ulPoolMemoryUsage, uint32 unPoolPeakInstanceCount, uint64 ulPoolPeakMemoryUsage ) = 0;
+};
+
+// A class for registering functions that will print memory usage information
+typedef void (*DumpMemFn_t)( IDisplayMemPoolStats * );
+class CDumpMemFnReg
+{
+public:
+ static CDumpMemFnReg *sm_Head;
+
+ CDumpMemFnReg( DumpMemFn_t fn )
+ : m_fn( fn ),
+ m_pNext( sm_Head )
+ {
+ sm_Head = this;
+ }
+
+ DumpMemFn_t m_fn;
+ CDumpMemFnReg *m_pNext;
+};
+
+// Helper macros for creating and using CClassMemoryPool on our frequently allocated objects
+#define DECLARE_CLASS_MEMPOOL( className ) \
+private: \
+ static CUtlMemoryPool sm_classMemPool; \
+public: \
+ static void* operator new ( size_t nSize ); \
+ static void* operator new ( size_t nSize, int nBlockUse, const char *pFileName, int nLine ); \
+ static void operator delete ( void *pMem ); \
+ static void DumpMemStats( IDisplayMemPoolStats *pDisplayer ); \
+
+
+#define IMPLEMENT_CLASS_MEMPOOL( className, initSize, growMode ) \
+CUtlMemoryPool className::sm_classMemPool( sizeof( className ), ( initSize ), ( growMode ), MEM_ALLOC_CLASSNAME( className ) ); \
+ \
+void* className::operator new ( size_t nSize ) \
+{ \
+ if ( nSize != sizeof( className ) ) \
+ { \
+ EmitError( SPEW_CONSOLE, #className"::operator new() called on wrong size! Expected %llu, Got %llu\n", (uint64)sizeof( className ), (uint64)nSize ); \
+ return NULL; \
+ } \
+ \
+ return sm_classMemPool.Alloc(); \
+} \
+ \
+void* className::operator new ( size_t nSize, int nBlockUse, const char *pFileName, int nLine ) \
+{ \
+ if ( nSize != sizeof( className ) ) \
+ { \
+ EmitError( SPEW_CONSOLE, #className"::operator new() called on wrong size! Expected %llu, Got %llu\n", (uint64)sizeof( className ), (uint64)nSize ); \
+ return NULL; \
+ } \
+ \
+ return sm_classMemPool.Alloc(); \
+} \
+ \
+void className::operator delete ( void *pMem ) \
+{ \
+ sm_classMemPool.Free( (className *)pMem ); \
+} \
+ \
+void className::DumpMemStats( IDisplayMemPoolStats *pDisplayer ) \
+{ \
+ Assert( pDisplayer ); \
+ pDisplayer->Display \
+ ( \
+ #className, \
+ sizeof( className ), \
+ sm_classMemPool.Count(), \
+ sm_classMemPool.Count() * sizeof( className ), \
+ ( ( sm_classMemPool.PeakCount() + ( initSize ) ) / ( initSize ) ) * ( initSize ) , \
+ ( ( sm_classMemPool.PeakCount() + ( initSize ) ) / ( initSize ) ) * ( initSize ) * sizeof( className ) \
+ ); \
+} \
+ \
+static CDumpMemFnReg s_##className##RegDumpMemory( &className::DumpMemStats );
+
+// useful macro for rendering an IP
+#define iptod(x) ((x)>>24&0xff), ((x)>>16&0xff), ((x)>>8&0xff), ((x)&0xff)
+
+#endif // MISC_H
diff --git a/gcsdk/steamextra/rtime.cpp b/gcsdk/steamextra/rtime.cpp
new file mode 100644
index 0000000..14081ce
--- /dev/null
+++ b/gcsdk/steamextra/rtime.cpp
@@ -0,0 +1,1216 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Encapsulates real world (wall clock) time
+//
+//=============================================================================
+
+#include "stdafx.h"
+#ifdef POSIX
+#include <sys/time.h>
+#else
+#include "winlite.h"
+#endif
+#include "rtime.h"
+#include <time.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#if defined( WIN32 ) || defined( _PS3 )
+// This strptime implementation is taken from the Goolge Site Map Generator project:
+
+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Implement strptime under windows
+static const char* kWeekFull[] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+};
+
+static const char* kWeekAbbr[] = {
+ "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat"
+};
+
+static const char* kMonthFull[] = {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+};
+
+static const char* kMonthAbbr[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char* _parse_num(const char* s, int low, int high, int* value) {
+ const char* p = s;
+ for (*value = 0; *p != NULL && V_isdigit(*p); ++p) {
+ *value = (*value) * 10 + static_cast<int>(*p) - static_cast<int>('0');
+ }
+
+ if (p == s || *value < low || *value > high) return NULL;
+ return p;
+}
+
+static char* _strptime(const char *s, const char *format, struct tm *tm) {
+ while (*format != NULL && *s != NULL) {
+ if (*format != '%') {
+ if (*s != *format) return NULL;
+
+ ++format;
+ ++s;
+ continue;
+ }
+
+ ++format;
+ int len = 0;
+ switch (*format) {
+ // weekday name.
+ case 'a':
+ case 'A':
+ tm->tm_wday = -1;
+ for (int i = 0; i < 7; ++i) {
+ len = static_cast<int>(strlen(kWeekAbbr[i]));
+ if (V_strnicmp(kWeekAbbr[i], s, len) == 0) {
+ tm->tm_wday = i;
+ break;
+ }
+
+ len = static_cast<int>(strlen(kWeekFull[i]));
+ if ( V_strnicmp(kWeekFull[i], s, len) == 0) {
+ tm->tm_wday = i;
+ break;
+ }
+ }
+ if (tm->tm_wday == -1) return NULL;
+ s += len;
+ break;
+
+ // month name.
+ case 'b':
+ case 'B':
+ case 'h':
+ tm->tm_mon = -1;
+ for (int i = 0; i < 12; ++i) {
+ len = static_cast<int>(strlen(kMonthAbbr[i]));
+ if ( V_strnicmp(kMonthAbbr[i], s, len) == 0) {
+ tm->tm_mon = i;
+ break;
+ }
+
+ len = static_cast<int>(strlen(kMonthFull[i]));
+ if ( V_strnicmp(kMonthFull[i], s, len) == 0) {
+ tm->tm_mon = i;
+ break;
+ }
+ }
+ if (tm->tm_mon == -1) return NULL;
+ s += len;
+ break;
+
+ // month [1, 12].
+ case 'm':
+ s = _parse_num(s, 1, 12, &tm->tm_mon);
+ if (s == NULL) return NULL;
+ --tm->tm_mon;
+ break;
+
+ // day [1, 31].
+ case 'd':
+ case 'e':
+ s = _parse_num(s, 1, 31, &tm->tm_mday);
+ if (s == NULL) return NULL;
+ break;
+
+ // hour [0, 23].
+ case 'H':
+ s = _parse_num(s, 0, 23, &tm->tm_hour);
+ if (s == NULL) return NULL;
+ break;
+
+ // minute [0, 59]
+ case 'M':
+ s = _parse_num(s, 0, 59, &tm->tm_min);
+ if (s == NULL) return NULL;
+ break;
+
+ // seconds [0, 60]. 60 is for leap year.
+ case 'S':
+ s = _parse_num(s, 0, 60, &tm->tm_sec);
+ if (s == NULL) return NULL;
+ break;
+
+ // year [1900, 9999].
+ case 'Y':
+ s = _parse_num(s, 1900, 9999, &tm->tm_year);
+ if (s == NULL) return NULL;
+ tm->tm_year -= 1900;
+ break;
+
+ // year [0, 99].
+ case 'y':
+ s = _parse_num(s, 0, 99, &tm->tm_year);
+ if (s == NULL) return NULL;
+ if (tm->tm_year <= 68) {
+ tm->tm_year += 100;
+ }
+ break;
+ // arbitray whitespace.
+ case 't':
+ case 'n':
+ while (V_isspace(*s)) ++s;
+ break;
+
+ // '%'.
+ case '%':
+ if (*s != '%') return NULL;
+ ++s;
+ break;
+
+ // All the other format are not supported.
+ default:
+ AssertMsg( false, "Invalid format string to strptime!" );
+ return NULL;
+ }
+ ++format;
+ }
+
+ if (*format != NULL) {
+ return NULL;
+ } else {
+ return const_cast<char*>(s);
+ }
+}
+
+char* strptime(const char *buf, const char *fmt, struct tm *tm) {
+ return _strptime(buf, fmt, tm);
+}
+#endif // WIN32
+
+
+// Our cached copy of the current time
+RTime32 CRTime::sm_nTimeLastSystemTimeUpdate = 0; // initialize to large negative value to trigger immediate FileTimeCur update
+char CRTime::sm_rgchLocalTimeCur[16]="";
+char CRTime::sm_rgchLocalDateCur[16]="";
+RTime32 CRTime::sm_nTimeCur = 0;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CRTime::CRTime()
+{
+ if ( sm_nTimeCur == 0 )
+ {
+ sm_nTimeCur = time(NULL);
+ }
+
+ m_nStartTime = sm_nTimeCur;
+ m_bGMT = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the amount of time that's passed between our time and the
+// current time.
+// Output: Time that's passed between our time and the current time
+//-----------------------------------------------------------------------------
+int CRTime::CSecsPassed() const
+{
+ return( sm_nTimeCur - m_nStartTime );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates our current time value. We only
+// update the time once per frame-- the rest of the time, we just
+// access a cached copy of the time.
+// NOTE: This should only be called once per frame.
+//-----------------------------------------------------------------------------
+void CRTime::UpdateRealTime()
+{
+ // BUGBUG Alfred: update this less often than once per frame?
+ RTime32 nTimePrev = sm_nTimeCur;
+ sm_nTimeCur = time(NULL);
+
+ if ( sm_nTimeCur < nTimePrev )
+ {
+ // time can go backwards sometimes if clock sync adjusts system time; warn when this happens
+ EmitInfo( SPEW_SYSTEM_MISC, SPEW_ALWAYS, LOG_ALWAYS, "Warning: system time went backward by %d seconds\n", ( nTimePrev - sm_nTimeCur ) );
+ }
+
+ // update our time from file time once per second
+ if ( sm_nTimeCur - sm_nTimeLastSystemTimeUpdate >= 1 )
+ {
+#ifdef _WIN32
+ // get the local time, generate time & date strings and cache the strings, as we will need these
+ // frequently for logs.
+ SYSTEMTIME systemTimeLocal;
+ GetLocalTime( &systemTimeLocal );
+ GetTimeFormat( LOCALE_USER_DEFAULT, 0, &systemTimeLocal, "HH:mm:ss", sm_rgchLocalTimeCur, Q_ARRAYSIZE( sm_rgchLocalTimeCur ) );
+ GetDateFormat( LOCALE_USER_DEFAULT, 0, &systemTimeLocal, "MM/dd/yy", sm_rgchLocalDateCur, Q_ARRAYSIZE( sm_rgchLocalDateCur ) );
+#elif defined(POSIX)
+ time_t now;
+ time( &now );
+ struct tm tmStruct;
+ struct tm *localTime = Plat_gmtime( &now, &tmStruct );
+ strftime( sm_rgchLocalTimeCur, Q_ARRAYSIZE( sm_rgchLocalTimeCur ), "%H:%M:%S", localTime );
+ strftime( sm_rgchLocalDateCur, Q_ARRAYSIZE( sm_rgchLocalDateCur ), "%m/%d/%y", localTime );
+#else
+#error "Implement me"
+#endif
+ sm_nTimeLastSystemTimeUpdate = sm_nTimeCur;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the system clock on this box to specified world time
+// Input: rTime32Current - world time to set
+//-----------------------------------------------------------------------------
+void CRTime::SetSystemClock( RTime32 rTime32Current )
+{
+#ifdef _WIN32
+ FILETIME fileTime;
+ SYSTEMTIME systemTime = {0};
+ // convert from seconds since 1/1/1970 to filetime (100 nanoseconds since 1/1/1601) with this magic formula courtesy of MSDN
+ uint64 ulTmp = ( ( (uint64) rTime32Current ) * 10 * k_nMillion ) + 116444736000000000;
+ fileTime.dwLowDateTime = (DWORD) ulTmp;
+ fileTime.dwHighDateTime = ulTmp >> 32;
+
+ // convert from filetime to system time (note this also does time zone conversion to UTC)
+ BOOL bRet = FileTimeToSystemTime( &fileTime, &systemTime );
+ Assert( bRet ); // should never fail
+ if ( !bRet ) // but if it does, don't set system clock to garbage
+ return;
+
+ // set system time in UTC
+ bRet = SetSystemTime( &systemTime );
+ Assert( bRet );
+
+ // update our cached time
+ sm_nTimeCur = rTime32Current;
+#else
+ Assert( !"Not implemented" );
+#endif // _WIN32
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Renders the time
+// Output : ptr to time string
+//-----------------------------------------------------------------------------
+const char* CRTime::Render( char (&buf)[k_RTimeRenderBufferSize] ) const
+{
+ return Render( m_nStartTime, buf );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Renders the time - static function
+// Input : rTime32 - time to render
+// Output : ptr to time string
+//-----------------------------------------------------------------------------
+const char* CRTime::Render( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize] )
+{
+ if ( !buf )
+ {
+ Assert( buf );
+ return nullptr;
+ }
+
+ // The return value string contains exactly 26 characters and has the form: Wed Jan 02 02:03:55 1980\n\0
+ time_t tTime = rTime32;
+ char pchTime[32];
+ if ( !Plat_ctime( &tTime, pchTime, Q_ARRAYSIZE( pchTime ) ) )
+ return 0;
+
+ // Remove '\n'
+ Assert( Q_strlen( pchTime ) == 25 );
+ pchTime[ 24 ] = '\0';
+
+ if ( rTime32 == k_RTime32Infinite )
+ Q_strncpy( buf, "Infinite time value", k_RTimeRenderBufferSize );
+ else if ( rTime32 == k_RTime32Nil )
+ Q_strncpy( buf, "Nil time value", k_RTimeRenderBufferSize );
+ else if ( rTime32 < k_RTime32MinValid )
+ Q_strncpy( buf, "Invalid time value", k_RTimeRenderBufferSize );
+ else
+ Q_strncpy( buf, pchTime, k_RTimeRenderBufferSize );
+
+ return buf;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the calendar year (absolute) for the current time
+//-----------------------------------------------------------------------------
+int CRTime::GetYear() const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_year + 1900;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the calendar month (0-11) for the current time
+//-----------------------------------------------------------------------------
+int CRTime::GetMonth() const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_mon;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the day of the calendar year (0-365) for the current time
+//-----------------------------------------------------------------------------
+int CRTime::GetDayOfYear() const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_yday;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the day of the month (1-31) for the current time
+//-----------------------------------------------------------------------------
+int CRTime::GetDayOfMonth() const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_mday;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the day of the week (0-6, 0=Sunday) for the current time
+//-----------------------------------------------------------------------------
+int CRTime::GetDayOfWeek() const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_wday;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the current hour (0-23)
+//-----------------------------------------------------------------------------
+int CRTime::GetHour( ) const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_hour;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the current minute value (0-59)
+//-----------------------------------------------------------------------------
+int CRTime::GetMinute( ) const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_min;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the current second value (0-59)
+//-----------------------------------------------------------------------------
+int CRTime::GetSecond() const
+{
+ time_t timeCur = m_nStartTime;
+ struct tm tmStruct;
+ struct tm *ptmCur = m_bGMT ? Plat_gmtime( &timeCur, &tmStruct ) : Plat_localtime( &timeCur, &tmStruct );
+ return ptmCur->tm_sec;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the ISO week number
+//-----------------------------------------------------------------------------
+int CRTime::GetISOWeekOfYear() const
+{
+ int nDay = GetDayOfYear() - ( 1 + GetDayOfWeek() );
+ int nISOWeek = nDay / 7;
+ return nISOWeek;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: let me know if this is a leap year or not
+//-----------------------------------------------------------------------------
+/* static */ bool CRTime::BIsLeapYear( int nYear )
+{
+ // every for years, unless it is a century; or if it is every 4th century
+ if ( ( nYear % 4 == 0 && nYear % 100 != 0) || nYear % 400 == 0)
+ return true; /* leap */
+ else
+ return false; /* no leap */
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to given sting
+// Using a format string to convert
+// Input: pchFmt - Format string that describes how to parse the value
+// YY or YYYY is year, MM month, DD day of the month,
+// hh mm ss is hour minute second.
+// Z0000 is a time-zone offset, eg -0700.
+// Everything except YY is optional (will be considered 0 if not given)
+// pchValue - String containing the value to covert
+// Output: RTime32
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32FromFmtString( const char *pchFmt, const char* pchValue )
+{
+ struct tm tm;
+
+ char rgchNum[8];
+ char rgchValue[64];
+
+ Q_memset( &tm, 0x0, sizeof( tm ) );
+ Q_strncpy( rgchValue, pchValue, sizeof( rgchValue) );
+
+ int cchFmt = Q_strlen( pchFmt );
+ int cchValue = Q_strlen( rgchValue );
+ if ( cchFmt != cchValue || cchFmt < 4 )
+ {
+ Assert( false );
+ return k_RTime32Nil;
+ }
+
+ const char *pchYYYY = Q_strstr( pchFmt, "YYYY" );
+ const char *pchYY = Q_strstr( pchFmt, "YY" );
+ const char *pchMM = Q_strstr( pchFmt, "MM" );
+ const char *pchMnt = Q_strstr( pchFmt, "Mnt" );
+ const char *pchDD = Q_strstr( pchFmt, "DD" );
+ const char *pchThh = Q_strstr( pchFmt, "hh" );
+ const char *pchTmm = Q_strstr( pchFmt, "mm" );
+ const char *pchTss = Q_strstr( pchFmt, "ss" );
+ const char *pchTzone = Q_strstr( pchFmt, "Z0000" );
+
+ if ( pchYYYY )
+ {
+ pchYYYY = rgchValue + ( pchYYYY - pchFmt );
+ Q_strncpy( rgchNum, pchYYYY, 5 );
+ tm.tm_year = strtol( rgchNum, 0, 10 ) - 1900;
+ }
+ else if ( pchYY )
+ {
+ pchYY = rgchValue + ( pchYY - pchFmt );
+ Q_strncpy( rgchNum, pchYY, 3 );
+ tm.tm_year = strtol( rgchNum, 0, 10 ) + 100;
+ }
+ else
+ return k_RTime32Nil; // must have a year
+
+ if ( pchMM )
+ {
+ pchMM = rgchValue + ( pchMM - pchFmt );
+ Q_strncpy( rgchNum, pchMM, 3 );
+ tm.tm_mon = strtol( rgchNum, 0, 10 ) - 1;
+ }
+ if ( pchMnt )
+ {
+ static const char *rgszMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ pchMnt = rgchValue + ( pchMnt - pchFmt );
+ int i;
+ for ( i = 0; i < 12; i++ )
+ {
+ if ( !V_strnicmp( rgszMonthNames[i], pchMnt, 3 ) )
+ break;
+ }
+ if ( i < 12 )
+ tm.tm_mon = i;
+ }
+ if ( pchDD )
+ {
+ pchDD = rgchValue + (pchDD - pchFmt );
+ Q_strncpy( rgchNum, pchDD, 3 );
+ tm.tm_mday = strtol( rgchNum, 0, 10 );
+ }
+ if ( pchThh )
+ {
+ pchThh = rgchValue + ( pchThh - pchFmt );
+ Q_strncpy( rgchNum, pchThh, 3 );
+ tm.tm_hour = strtol( rgchNum, 0, 10 );
+ }
+ if ( pchTmm )
+ {
+ pchTmm = rgchValue + ( pchTmm - pchFmt );
+ Q_strncpy( rgchNum, pchTmm, 3 );
+ tm.tm_min = strtol( rgchNum, 0, 10 );
+ }
+ if ( pchTss )
+ {
+ pchTss = rgchValue + (pchTss - pchFmt );
+ Q_strncpy( rgchNum, pchTss, 3 );
+ tm.tm_sec = strtol( rgchNum, 0, 10 );
+ }
+ if ( pchTzone )
+ {
+ long nOffset = 0;
+ pchTzone = rgchValue + (pchTzone - pchFmt);
+ Q_strncpy( rgchNum, pchTzone, 6 );
+ nOffset = strtol( rgchNum, 0, 10 );
+ tm.tm_hour -= nOffset / 100; // to go from -0700 to UTC, need to ADD seven
+
+ // is this a sub-hour timezone? eg +0545 Kathmandu
+ int nMinutesOffset = nOffset % 100;
+ if ( nMinutesOffset )
+ tm.tm_min -= nMinutesOffset;
+
+ // OK, so this is somewhat lame: mktime assumes our tm units are in LOCAL time.
+ // However, we have just created a UTC time by using the supplied timezone offset.
+ // The rational thing to do here would be to call mkgmtime() instead of mktime(),
+ // but that function isn't available in unix-land.
+ // SO, instead we will MANUALLY convert this tm back to local time
+
+#if ( defined( _MSC_VER ) && _MSC_VER >= 1900 )
+ #define timezone _timezone
+ #define daylight _daylight
+#endif
+
+ // subtract timezone, which is in SECONDS. timezone is (UTC - local), so local = UTC - timezone
+ tm.tm_sec -= timezone;
+ // timezone does NOT account for DST, so if we are in DST, we need to ADD an hour.
+ // This is because the value of timezone we subtracted was one hour TOO LARGE
+ tm.tm_hour += daylight ? 1 : 0;
+
+ }
+
+ // We don't know if DST is in effect, let the CRT
+ // figure it out
+ tm.tm_isdst = -1;
+
+ return mktime( &tm );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to given sting which is
+// expected to be in one of the common HTTP date formats.
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32FromHTTPDateString( const char* pchValue )
+{
+ // First format here is RFC 822/1123 format
+ struct tm tm;
+ if ( strptime( pchValue, "%a, %e %b %Y %H:%M:%S", &tm ) )
+ {
+ return Plat_timegm( &tm );
+ }
+
+ // If that failed, try RFC 850/1036 format
+ if ( strptime( pchValue, "%a, %e-%b-%y %H:%M:%S", &tm ) )
+ {
+ return Plat_timegm( &tm );
+ }
+
+ // If that also failed, give up
+ return k_RTime32Nil;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Parse time from string RFC3339 format (assumes UTC)
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32FromRFC3339UTCString( const char* pchValue )
+{
+
+ // UTC only from RFC 3339. Should be 2005-05-15T17:11:51Z
+ struct tm tm;
+ if ( strptime( pchValue, "%Y-%m-%dT%H:%M:%SZ", &tm ) )
+ {
+ return Plat_timegm( &tm );
+ }
+
+ // If that also failed, give up
+ return k_RTime32Nil;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Output time in RFC3339 format (assumes UTC)
+//-----------------------------------------------------------------------------
+// STATIC
+const char* CRTime::RTime32ToRFC3339UTCString( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize] )
+{
+ if ( !buf )
+ {
+ Assert( buf );
+ return nullptr;
+ }
+
+ // Store the result in a temporary buffer, so that you can use several in a single printf.
+ time_t tTime = rTime32;
+ struct tm tmStruct;
+ struct tm *ptm = Plat_gmtime( &tTime, &tmStruct );
+
+ if ( rTime32 == k_RTime32Nil || !ptm )
+ return "NIL";
+
+ if ( rTime32 == k_RTime32Infinite )
+ return "Infinite time value";
+
+ if ( rTime32 < k_RTime32MinValid || !ptm )
+ return "Invalid time value";
+
+ Q_snprintf( buf, k_RTimeRenderBufferSize, "%04u-%02u-%02uT%02u:%02u:%02uZ", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec );
+ return buf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to given sting
+// "YYYY-MM-DD hh:mm:ss" (copied from sqlhelpers.cpp)
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32FromString( const char* pszValue )
+{
+ struct tm tm;
+
+ char num[5];
+ char szValue[64];
+
+ Q_memset( &tm, 0x0, sizeof( tm ) );
+ Q_strncpy( szValue, pszValue, sizeof( szValue) );
+
+ const char *str= szValue;
+
+ num[0] =*str++; num[1] =*str++; num[2] =*str++; num[3] =*str++; num[4] = 0;
+ tm.tm_year = strtol( num, 0, 10 ) - 1900;
+ if (*str == '-') str++;
+ num[0] = *str++; num[1] = *str++; num[2] = 0;
+ tm.tm_mon = strtol( num, 0, 10 ) - 1;
+ if (*str == '-') str++;
+ num[0] = *str++; num[1] = *str++; num[2] = 0;
+ tm.tm_mday = strtol( num, 0, 10 );
+
+ if ( *str != 0 )
+ {
+ // skip an optional space or T between date and time
+ if ( *str == ' ' || *str == 'T' )
+ str++;
+
+ // time is given too
+ num[0] = *str++; num[1] = *str++; num[2] = 0;
+ tm.tm_hour = strtol( num, 0, 10 );
+ if (*str == ':') str++;
+ num[0] = *str++; num[1] = *str++; num[2] = 0;
+ tm.tm_min = strtol( num, 0, 10 );
+ if (*str == ':') str++;
+ num[0] = *str++; num[1] = *str++; num[2] = 0;
+ tm.tm_sec = strtol( num, 0, 10 );
+ }
+ tm.tm_isdst = -1;
+
+ return mktime( &tm );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns a static string "YYYY-MM-DD hh:mm:ss" for given RTime32
+// Input: rTime32 -
+// bNoPunct - No dashes, colons or spaces will be in the output string
+// bOnlyDate - Only output the date
+// Output: const char * -- only usable till the next yield
+//-----------------------------------------------------------------------------
+// STATIC
+const char* CRTime::RTime32ToString( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize], bool bNoPunct /*=false*/, bool bOnlyDate /*= false*/ )
+{
+ if ( !buf )
+ {
+ return nullptr;
+ }
+
+ // Store the result in a temporary buffer, so that you can use several in a single printf.
+ time_t tTime = rTime32;
+ struct tm tmStruct;
+ struct tm *ptm = Plat_localtime( &tTime, &tmStruct );
+
+ const char *pchOnlyDateFmt = bNoPunct ? "%04u%02u%02u" : "%04u-%02u-%02u";
+ const char *pchDateTimeFmt = bNoPunct ? "%04u%02u%02u%02u%02u%02u" : "%04u-%02u-%02u %02u:%02u:%02u";
+ if ( rTime32 == k_RTime32Nil || !ptm )
+ return "NIL";
+
+ if ( rTime32 == k_RTime32Infinite )
+ return "Infinite time value";
+
+ if ( rTime32 < k_RTime32MinValid || !ptm )
+ return "Invalid time value";
+
+ if ( bOnlyDate )
+ {
+ Q_snprintf( buf, k_RTimeRenderBufferSize, pchOnlyDateFmt,
+ ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday );
+ }
+ else
+ {
+ Q_snprintf( buf, k_RTimeRenderBufferSize, pchDateTimeFmt,
+ ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
+ ptm->tm_hour, ptm->tm_min, ptm->tm_sec );
+ }
+
+ return buf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns a static string like "Aug 21" for given RTime32
+// Input: rTime32 -
+//
+// Output: const char * -- only usable till the next yield
+//-----------------------------------------------------------------------------
+// STATIC
+const char* CRTime::RTime32ToDayString( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize], bool bGMT )
+{
+ if ( !buf )
+ {
+ return nullptr;
+ }
+
+ // Store the result in a temporary buffer, so that you can use several in a single printf.
+ time_t tTime = rTime32;
+ struct tm tmStruct;
+ struct tm *ptm = bGMT ? Plat_gmtime( &tTime, &tmStruct ) : Plat_localtime( &tTime, &tmStruct );
+
+ DbgVerify( strftime( buf, k_RTimeRenderBufferSize, "%b %d", ptm ) );
+ return buf;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to the beginning of
+// the day represented by rtime32
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32BeginningOfDay( const RTime32 rtime32 )
+{
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ // midnight
+ ptmCur->tm_hour = 0;
+ ptmCur->tm_min = 0;
+ ptmCur->tm_sec = 0;
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ return mktime( ptmCur );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to the beginning of
+// the next day after rtime32
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32BeginningOfNextDay( const RTime32 rtime32 )
+{
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ // It will move to the next month etc if need be
+ ptmCur->tm_mday++;
+
+ // midnight
+ ptmCur->tm_hour = 0;
+ ptmCur->tm_min = 0;
+ ptmCur->tm_sec = 0;
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ return mktime( ptmCur );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to the first day of
+// the month indicated by rtime32
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32FirstDayOfMonth( const RTime32 rtime32 )
+{
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ // first day of month
+ ptmCur->tm_mday = 1;
+
+ // midnight
+ ptmCur->tm_hour = 0;
+ ptmCur->tm_min = 0;
+ ptmCur->tm_sec = 0;
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ return mktime( ptmCur );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to the last day of
+// the month indicated by rtime32
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32LastDayOfMonth( const RTime32 rtime32 )
+{
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ // Zeroth day of month N becomes last day of month (N-1)
+ ptmCur->tm_mon++;
+ ptmCur->tm_mday = 0;
+
+ // midnight
+ ptmCur->tm_hour = 0;
+ ptmCur->tm_min = 0;
+ ptmCur->tm_sec = 0;
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ return mktime( ptmCur );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to the first day of
+// the month after the one indicated by rtime32
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32FirstDayOfNextMonth( const RTime32 rtime32 )
+{
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ ptmCur->tm_mon++;
+ ptmCur->tm_mday = 1;
+
+ // midnight
+ ptmCur->tm_hour = 0;
+ ptmCur->tm_min = 0;
+ ptmCur->tm_sec = 0;
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ return mktime( ptmCur );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to the last day of
+// the month after the one indicated by rtime32
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32LastDayOfNextMonth( const RTime32 rtime32 )
+{
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ // use zeroth-day trick - skip 2 months then back a day
+ ptmCur->tm_mon += 2;
+ ptmCur->tm_mday = 0;
+
+ // midnight
+ ptmCur->tm_hour = 0;
+ ptmCur->tm_min = 0;
+ ptmCur->tm_sec = 0;
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ return mktime( ptmCur );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculate and return a time value corresponding to the Nth day of
+// the month. If that month only has K days, K < N, it will return
+// the Kth day. The input should be reasonable (don't ask for the -5th
+// day of the month).
+//
+// Input: rtime32 - Time representing some time in the month interested in
+// nDay - The day of that month you want the return to be set to
+//
+// Return: Time value equal to midnight on that day.
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32NthDayOfMonth( const RTime32 rtime32, int nDay )
+{
+ Assert( nDay > 0 );
+ Assert( nDay < 32 );
+
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ int nCurMonth = ptmCur->tm_mon;
+
+ ptmCur->tm_mday = nDay;
+
+ // midnight
+ ptmCur->tm_hour = 0;
+ ptmCur->tm_min = 0;
+ ptmCur->tm_sec = 0;
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ // This call will modify ptmCur in-place
+ time_t timeThen = mktime( ptmCur );
+
+ // See if the month changed
+ if ( ptmCur->tm_mon != nCurMonth )
+ {
+ // use zeroth-day trick to just get the last day of this month
+ ptmCur->tm_mday = 0;
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+ timeThen = mktime( ptmCur );
+ }
+
+ return timeThen;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Add X months to the current date, and return the Nth day of that
+// month.
+//
+// Input: nNthDayOfMonth - Day of the target month to return a date for
+// rtime32StartDate - Time value to add X months to
+// nMonthsToAdd - X
+//
+// Return: Time value equal to midnight on that day.
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32MonthAddChooseDay( int nNthDayOfMonth, RTime32 rtime32StartDate, int nMonthsToAdd )
+{
+ // Get the first day of start month
+ RTime32 rtime32FirstDayOfStartMonth = CRTime( rtime32StartDate ).GetFirstDayOfMonth();
+
+ // Add X months to that - guaranteed to be correct month
+ RTime32 rtime32FirstDayOfTargetMonth = CRTime::RTime32DateAdd( rtime32FirstDayOfStartMonth, nMonthsToAdd, k_ETimeUnitMonth );
+
+ // Then get the Nth day of that month
+ RTime32 rtime32Target = CRTime::RTime32NthDayOfMonth( rtime32FirstDayOfTargetMonth, nNthDayOfMonth );
+
+ return rtime32Target;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Add or subtract N units of time from the current value.
+// Units may be days, weeks, seconds, etc
+// Input: rtime32 - Reference time
+// nAmount - Number of units to add (neg for subtract)
+// eTimeFlagAmountType - Indicates what units are on nAmount
+//
+// Return: The newly calculated offset time (the input is unmodified)
+//-----------------------------------------------------------------------------
+// STATIC
+RTime32 CRTime::RTime32DateAdd( const RTime32 rtime32, int nAmount, ETimeUnit eTimeAmountType )
+{
+ time_t timeCur = rtime32;
+ struct tm tmStruct;
+ struct tm *ptmCur = Plat_localtime( &timeCur, &tmStruct );
+ if ( !ptmCur )
+ return k_RTime32Nil;
+
+ // mktime() is smart enough to take day-of-month values that are out of range and adjust
+ // everything to make sense. So you can go back 3 weeks by just subtracting 21 from tm_mday.
+ switch ( eTimeAmountType )
+ {
+ default:
+ AssertMsg( false, "Bad flag in RTime32DateAdd" );
+ break;
+ case k_ETimeUnitForever:
+ return k_RTime32Infinite;
+ case k_ETimeUnitYear:
+ ptmCur->tm_year += nAmount;
+ break;
+ case k_ETimeUnitMonth:
+ ptmCur->tm_mon += nAmount;
+ break;
+ case k_ETimeUnitWeek:
+ ptmCur->tm_mday += 7 * nAmount;
+ break;
+ case k_ETimeUnitDay:
+ ptmCur->tm_mday += nAmount;
+ break;
+ case k_ETimeUnitHour:
+ ptmCur->tm_hour += nAmount;
+ break;
+ case k_ETimeUnitMinute:
+ ptmCur->tm_min += nAmount;
+ break;
+ case k_ETimeUnitSecond:
+ ptmCur->tm_sec += nAmount;
+ break;
+ }
+
+ // Let it compute DST
+ ptmCur->tm_isdst = -1;
+
+ return mktime( ptmCur );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Compare two times and evaluate what calendar boundaries have
+// been crossed (eg day, month, hour) between the two times.
+//
+// Note: in general, the crossing of a large boundary will be accompanied
+// by the crossing of all smaller boundaries. The exception is Week:
+// the Week boundary is from Saturday to Sunday, and it is possible to
+// go over a Month or Year boundary without beginning a new week.
+//
+// So, the return value is the largest time boundary that was crossed.
+// However, the pbWeekChanged value will be set to indicate if the week
+// changed in cases where the return value is Month or Year.
+//
+// Input: unTime1 - First time value
+// unTime2 - Second time value
+// pbWeekChanged - Indicates if the Week changed
+//
+// Return: Largest time boundary crossed
+//-----------------------------------------------------------------------------
+// STATIC
+ETimeUnit CRTime::FindTimeBoundaryCrossings( RTime32 unTime1, RTime32 unTime2, bool *pbWeekChanged )
+{
+ time_t time1 = unTime1;
+ time_t time2 = unTime2;
+
+ // have to cache the first one locally, because it's a global object
+ struct tm tmStruct1;
+ struct tm *ptmTime1 = Plat_localtime( &time1, &tmStruct1 );
+ if ( !ptmTime1 )
+ return k_ETimeUnitForever;
+ struct tm _tmTime1 = *ptmTime1;
+ ptmTime1 = &_tmTime1;
+ struct tm tmStruct2;
+ struct tm *ptmTime2 = Plat_localtime( &time2, &tmStruct2 );
+ if ( !ptmTime2 )
+ return k_ETimeUnitForever;
+
+ // Need a little extra logic to find week boundaries
+ // Find this out first, because it may or may not be true even if a
+ // month / year boundary was crossed.
+ *pbWeekChanged = false;
+
+ // If the difference is more than 6 days, we crossed a week boundary
+ if ( ( ( unTime1 > unTime2 ) && ( ( unTime1 - unTime2 ) > k_cSecondsPerWeek ) )
+ || ( ( unTime2 > unTime1 ) && ( ( unTime2 - unTime1 ) > k_cSecondsPerWeek ) ) )
+ {
+ *pbWeekChanged = true;
+ }
+ else if ( ptmTime1->tm_yday != ptmTime2->tm_yday )
+ {
+ // Otherwise, we have to look at wday - if the later time
+ // has a lower or equal wday value, then we crossed a week boundary
+ if ( unTime2 > unTime1 )
+ {
+ if ( ptmTime2->tm_wday <= ptmTime1->tm_wday )
+ *pbWeekChanged = true;
+ }
+ else
+ {
+ if ( ptmTime1->tm_wday <= ptmTime2->tm_wday )
+ *pbWeekChanged = true;
+ }
+ }
+
+ // Evaluate larger boundaries first. As soon as we detect
+ // that we've crossed a boundary, we consider all smaller boundaries
+ // crossed too.
+
+ // Year
+ if ( ptmTime1->tm_year != ptmTime2->tm_year )
+ return k_ETimeUnitYear;
+
+ // Month
+ if ( ptmTime1->tm_mon != ptmTime2->tm_mon )
+ return k_ETimeUnitMonth;
+
+ // If the week changed, return that now
+ if ( *pbWeekChanged )
+ return k_ETimeUnitWeek;
+
+ // Day
+ if ( ptmTime1->tm_yday != ptmTime2->tm_yday )
+ return k_ETimeUnitDay;
+
+ // Hour
+ if ( ptmTime1->tm_hour != ptmTime2->tm_hour )
+ return k_ETimeUnitHour;
+
+ // If DST changed, make sure that we know an hour boundary was crossed
+ // (overlap from the "fall back" case may otherwise trick us)
+ if ( ptmTime1->tm_isdst != ptmTime2->tm_isdst )
+ return k_ETimeUnitHour;
+
+ // Minute
+ if ( ptmTime1->tm_min != ptmTime2->tm_min )
+ return k_ETimeUnitMinute;
+
+ // Second
+ if ( ptmTime1->tm_sec != ptmTime2->tm_sec )
+ return k_ETimeUnitSecond;
+
+ return k_ETimeUnitNone;
+
+}
+
diff --git a/gcsdk/steamextra/rtime.h b/gcsdk/steamextra/rtime.h
new file mode 100644
index 0000000..579cdca
--- /dev/null
+++ b/gcsdk/steamextra/rtime.h
@@ -0,0 +1,187 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Encapsulates real world (wall clock) time
+//
+//=============================================================================
+#ifndef RTIME_H
+#define RTIME_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#ifdef WIN32
+char* strptime(const char *s, const char *format, struct tm *tm);
+#endif
+
+#include <time.h>
+#include <ctype.h>
+#include <string.h>
+
+
+
+class CSTime;
+
+// Invalid time values
+const RTime32 k_RTime32Nil = 0;
+// time values between Nil and MinValid are available for special constants
+const RTime32 k_RTime32MinValid = 10;
+// infinite time value
+const RTime32 k_RTime32Infinite = 0x7FFFFFFF; //01-18-2038
+
+// Render buffer size
+const size_t k_RTimeRenderBufferSize = 25;
+
+// Flags for component fields. Longer durations must be > shorter ones
+// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE
+enum ETimeUnit
+{
+ k_ETimeUnitNone = 0,
+ k_ETimeUnitSecond = 1,
+ k_ETimeUnitMinute = 2,
+ k_ETimeUnitHour = 3,
+ k_ETimeUnitDay = 4,
+ k_ETimeUnitWeek = 5,
+ k_ETimeUnitMonth = 6,
+ k_ETimeUnitYear = 7,
+ k_ETimeUnitForever
+};
+
+// CRTime
+// This is our primary real time structure.
+// It offers 1 second resolution beginning on January 1, 1970 (i.e unix time)
+// This represents wall clock time
+class CRTime
+{
+public:
+ // default constructor initializes to the current time
+ CRTime();
+ CRTime( RTime32 nTime ) : m_nStartTime( nTime ), m_bGMT( false ) {}
+
+ void SetToCurrentTime() { m_nStartTime = sm_nTimeCur; }
+ void SetFromCurrentTime( int dSecOffset ) { m_nStartTime = sm_nTimeCur + dSecOffset; }
+
+ // Amount of seconds that have passed between this CRTime being set and the current wall clock time.
+ int CSecsPassed() const;
+
+ // Time accessors
+ RTime32 GetRTime32() const { return m_nStartTime; }
+ void SetRTime32( RTime32 rTime32 ) { m_nStartTime = rTime32; }
+
+ // Access our cached current time value
+ static void UpdateRealTime();
+ static void SetSystemClock( RTime32 nCurrentTime );
+ static RTime32 RTime32TimeCur() { return sm_nTimeCur; }
+
+ // Render
+ const char *Render( char (&buf)[k_RTimeRenderBufferSize] ) const;
+ static const char *Render( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize] );
+
+ // Return a representation of the current system time
+ static char *PchTimeCur() { return sm_rgchLocalTimeCur; }
+ // Return a representation of the current system date
+ static char *PchDateCur() { return sm_rgchLocalDateCur; }
+
+ // comparisons against other CRTime objects
+ bool operator==( const CRTime &val ) const { return val.m_nStartTime == m_nStartTime; }
+ bool operator<( const CRTime &val ) const { return m_nStartTime < val.m_nStartTime; }
+ bool operator<=( const CRTime &val ) const { return m_nStartTime <= val.m_nStartTime; }
+ bool operator>( const CRTime &val ) const { return m_nStartTime > val.m_nStartTime; }
+ bool operator>=( const CRTime &val ) const { return m_nStartTime >= val.m_nStartTime; }
+
+ // comparisons against RTime32 numbers (to avoid implicit construct/destruct of a temporary CRTime)
+ bool operator==( const RTime32 &val ) const { return m_nStartTime == val; }
+ bool operator<( const RTime32 &val ) const { return m_nStartTime < val; }
+ bool operator<=( const RTime32 &val ) const { return m_nStartTime <= val; }
+ bool operator>( const RTime32 &val ) const { return m_nStartTime > val; }
+ bool operator>=( const RTime32 &val ) const { return m_nStartTime >= val; }
+
+ const CRTime& operator=( const RTime32 &val ) { m_nStartTime = val; return *this; }
+ const CRTime& operator=( const CRTime &val ) { m_nStartTime = val.m_nStartTime; return *this; }
+ const CRTime operator+( const int &nVal ) { return m_nStartTime + nVal; }
+ // Add exactly X seconds to this time
+ const CRTime& operator+=( const int &nVal ) { m_nStartTime += nVal; return *this; }
+
+ // Component Details
+ int GetYear() const;
+ int GetMonth() const; // returns 0..11
+ int GetDayOfYear() const;
+ int GetDayOfMonth() const;
+ int GetDayOfWeek() const;
+ int GetHour() const;
+ int GetMinute() const;
+ int GetSecond() const;
+ int GetISOWeekOfYear() const;
+
+ // Handy references to nearby time boundaries
+ static RTime32 RTime32BeginningOfDay( const RTime32 ); // at 00:00:00
+ static RTime32 RTime32BeginningOfNextDay( const RTime32 ); // at 00:00:00
+ static RTime32 RTime32FirstDayOfMonth( const RTime32 ); // at 00:00:00
+ static RTime32 RTime32LastDayOfMonth( const RTime32 ); // at 00:00:00
+ static RTime32 RTime32FirstDayOfNextMonth( const RTime32 ); // at 00:00:00
+ static RTime32 RTime32LastDayOfNextMonth( const RTime32 ); // at 00:00:00
+
+ static bool BIsLeapYear( int nYear );
+ bool BIsLeapYear() const { return CRTime::BIsLeapYear( GetYear() ); }
+
+ // Parse time using a format string with strptime format
+ static RTime32 RTime32FromFmtString( const char *pchFmt, const char* pchValue );
+
+ // Parse time from string in standard HTTP date format
+ static RTime32 RTime32FromHTTPDateString( const char* pchValue );
+
+ // Parse time from string RFC3339 format (assumes UTC)
+ static RTime32 RTime32FromRFC3339UTCString( const char* pchValue );
+ static const char* RTime32ToRFC3339UTCString( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize] );
+
+ // parse time from string "YYYY-MM-DD hh:mm:ss" or just "YYYY-MM-DD", the ' ',':','-' are optional
+ static RTime32 RTime32FromString( const char* pszValue );
+
+ // turns RTime32 in a string like "YYYY-MM-DD hh:mm:ss"
+ static const char* RTime32ToString( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize], bool bNoPunct = false, bool bOnlyDate = false );
+
+ // turns RTime32 into a string like "Aug 21"
+ static const char* RTime32ToDayString( const RTime32 rTime32, char (&buf)[k_RTimeRenderBufferSize], bool bGMT = false );
+
+ // If the month only has K days, K < N, returns Kth day
+ static RTime32 RTime32NthDayOfMonth( const RTime32, int nDay ); // at 00:00:00
+
+ // Add X months but return the Nth day of that month. If the month only has K days, K < N, returns Kth day.
+ static RTime32 RTime32MonthAddChooseDay( int nNthDayOfMonth, RTime32 rtime32StartDate, int nMonthsToAdd );
+
+ RTime32 GetBeginningOfDay() const { return RTime32BeginningOfDay( m_nStartTime ); }
+ RTime32 GetBeginningOfNextDay() const { return RTime32BeginningOfNextDay( m_nStartTime ); }
+ RTime32 GetFirstDayOfMonth() const { return RTime32FirstDayOfMonth( m_nStartTime ); }
+ RTime32 GetLastDayOfMonth() const { return RTime32LastDayOfMonth( m_nStartTime ); }
+ RTime32 GetFirstDayOfNextMonth() const { return RTime32FirstDayOfNextMonth( m_nStartTime ); }
+ RTime32 GetLastDayOfNextMonth() const { return RTime32LastDayOfNextMonth( m_nStartTime ); }
+ RTime32 GetNthDayOfMonth( int nDay ) const { return RTime32NthDayOfMonth( m_nStartTime, nDay ); }
+ RTime32 MonthAddChooseDay( int nNthDayOfMonth, int nMonthsToAdd ) const { return RTime32MonthAddChooseDay( nNthDayOfMonth, m_nStartTime, nMonthsToAdd ); }
+
+ // Add or subtract N days, weeks, minutes, etc from the current time
+ static RTime32 RTime32DateAdd( const RTime32, int nAmount, ETimeUnit eTimeAmountType );
+ RTime32 DateAdd( int nAmount, ETimeUnit eTimeAmountType ) const { return RTime32DateAdd( m_nStartTime, nAmount, eTimeAmountType ); }
+
+ // Compare two times, and return what the largest time boundary crossed between the two was.
+ // Week boundaries do not line up with Month or Year boundaries, so you must rely on pbWeekChanged for them!
+ static ETimeUnit FindTimeBoundaryCrossings( RTime32 unTime1, RTime32 unTime2, bool *pbWeekChanged );
+
+ void SetToGMT( bool bUseGMT ) { m_bGMT = bUseGMT;}
+ bool BIsGMT() const { return m_bGMT; }
+
+private:
+ // prevent assignment or copy construction from the server time type
+ const CRTime& operator=( const CSTime &val ) { return *this; }
+ CRTime( const CSTime& ) {}
+
+ RTime32 m_nStartTime; // the time store by this instance (wall clock, in seconds)
+ static RTime32 sm_nTimeCur; // current system wide wall clock time
+
+ static char sm_rgchLocalTimeCur[16]; // string version of time for logging
+ static char sm_rgchLocalDateCur[16]; // string version of date for logging
+ static RTime32 sm_nTimeLastSystemTimeUpdate; // last time we updated above two logging strings
+
+ bool m_bGMT;
+};
+
+#endif // RTIME_H
diff --git a/gcsdk/steamextra/steam/isteamgamecoordinator.h b/gcsdk/steamextra/steam/isteamgamecoordinator.h
new file mode 100644
index 0000000..63f3c1b
--- /dev/null
+++ b/gcsdk/steamextra/steam/isteamgamecoordinator.h
@@ -0,0 +1,64 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: interface to the game coordinator for this application
+//
+//=============================================================================
+
+#ifndef ISTEAMGAMECOORDINATOR
+#define ISTEAMGAMECOORDINATOR
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "steam/steamtypes.h"
+#include "steam/steamclientpublic.h"
+#include "steam/isteamclient.h"
+
+// list of possible return values from the ISteamGameCoordinator API
+enum EGCResults
+{
+ k_EGCResultOK = 0,
+ k_EGCResultNoMessage = 1, // There is no message in the queue
+ k_EGCResultBufferTooSmall = 2, // The buffer is too small for the requested message
+ k_EGCResultNotLoggedOn = 3, // The client is not logged onto Steam
+ k_EGCResultInvalidMessage = 4, // Something was wrong with the message being sent with SendMessage
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Functions for sending and receiving messages from the Game Coordinator
+// for this application
+//-----------------------------------------------------------------------------
+class ISteamGameCoordinator
+{
+public:
+
+ // sends a message to the Game Coordinator
+ virtual EGCResults SendMessage( uint32 unMsgType, const void *pubData, uint32 cubData ) = 0;
+
+ // returns true if there is a message waiting from the game coordinator
+ virtual bool IsMessageAvailable( uint32 *pcubMsgSize ) = 0;
+
+ // fills the provided buffer with the first message in the queue and returns k_EGCResultOK or
+ // returns k_EGCResultNoMessage if there is no message waiting. pcubMsgSize is filled with the message size.
+ // If the provided buffer is not large enough to fit the entire message, k_EGCResultBufferTooSmall is returned
+ // and the message remains at the head of the queue.
+ virtual EGCResults RetrieveMessage( uint32 *punMsgType, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize ) = 0;
+
+};
+#define STEAMGAMECOORDINATOR_INTERFACE_VERSION "SteamGameCoordinator001"
+
+// callback notification - A new message is available for reading from the message queue
+struct GCMessageAvailable_t
+{
+ enum { k_iCallback = k_iSteamGameCoordinatorCallbacks + 1 };
+ uint32 m_nMessageSize;
+};
+
+// callback notification - A message failed to make it to the GC. It may be down temporarily
+struct GCMessageFailed_t
+{
+ enum { k_iCallback = k_iSteamGameCoordinatorCallbacks + 2 };
+};
+
+#endif // ISTEAMGAMECOORDINATOR
diff --git a/gcsdk/steamextra/steamid.cpp b/gcsdk/steamextra/steamid.cpp
new file mode 100644
index 0000000..6a4eb01
--- /dev/null
+++ b/gcsdk/steamextra/steamid.cpp
@@ -0,0 +1,729 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifdef TF
+#include "steamcommon.h"
+#define INCLUDED_STEAM2_USERID_STRUCTS
+#include "steam/steamclientpublic.h"
+#endif
+
+#include "stdafx.h"
+#ifdef HL1
+#include "steamcommon.h"
+#include "steam/steamclientpublic.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#ifndef UINT64_MAX
+#define UINT64_MAX ((uint64)-1)
+#endif
+
+static const char *DecimalToUint64( const char *pchStr, uint64 unLimit,
+ uint64 *punVal )
+{
+ const char *pchStart = pchStr;
+ uint64 unVal = 0;
+
+ while ( *pchStr >= '0' && *pchStr <= '9' )
+ {
+ uint64 unNext = unVal * 10;
+
+ if ( unNext < unVal )
+ {
+ // 64-bit overflow.
+ return NULL;
+ }
+
+ unVal = unNext + (uint64)( *pchStr - '0' );
+ if ( unVal > unLimit )
+ {
+ // Limit overflow.
+ return NULL;
+ }
+
+ pchStr++;
+ }
+ if ( pchStr == pchStart )
+ {
+ // No number at all.
+ return NULL;
+ }
+
+ *punVal = unVal;
+ return pchStr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : pchSteamID - text representation of a Steam ID
+//-----------------------------------------------------------------------------
+CSteamID::CSteamID( const char *pchSteamID, EUniverse eDefaultUniverse /* = k_EUniverseInvalid */ )
+{
+ SetFromString( pchSteamID, eDefaultUniverse );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Initializes a steam ID from a string
+// Input : pchSteamID - text representation of a Steam ID
+//-----------------------------------------------------------------------------
+void CSteamID::SetFromString( const char *pchSteamID, EUniverse eDefaultUniverse )
+{
+ uint nAccountID = 0;
+ uint nInstance = 1;
+ EUniverse eUniverse = eDefaultUniverse;
+ EAccountType eAccountType = k_EAccountTypeIndividual;
+#ifdef DBGFLAG_ASSERT
+ // TF Merge -- Assert is debug-only and we have unused variable warnings on :-/
+ const char *pchSteamIDString = pchSteamID;
+#endif
+ CSteamID StrictID;
+
+ StrictID.SetFromStringStrict( pchSteamID, eDefaultUniverse );
+
+ if ( *pchSteamID == '[' )
+ pchSteamID++;
+
+ // BUGBUG Rich use the Q_ functions
+ if (*pchSteamID == 'A')
+ {
+ // This is test only
+ pchSteamID++; // skip the A
+ eAccountType = k_EAccountTypeAnonGameServer;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+
+ if ( strchr( pchSteamID, '(' ) )
+ sscanf( strchr( pchSteamID, '(' ), "(%u)", &nInstance );
+ const char *pchColon = strchr( pchSteamID, ':' );
+ if ( pchColon && *pchColon != 0 && strchr( pchColon+1, ':' ))
+ {
+ sscanf( pchSteamID, "%u:%u:%u", (uint*)&eUniverse, &nAccountID, &nInstance );
+ }
+ else if ( pchColon )
+ {
+ sscanf( pchSteamID, "%u:%u", (uint*)&eUniverse, &nAccountID );
+ }
+ else
+ {
+ sscanf( pchSteamID, "%u", &nAccountID );
+ }
+
+ if ( nAccountID == 0 )
+ {
+ // i dont care what number you entered
+ CreateBlankAnonLogon(eUniverse);
+ }
+ else
+ {
+ InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
+ }
+ // Catch cases where we're allowing sloppy input that we
+ // might not want to allow.
+ AssertMsg1( this->operator==( StrictID ), "Steam ID does not pass strict parsing: '%s'", pchSteamIDString );
+ return;
+ }
+ else if (*pchSteamID == 'G')
+ {
+ pchSteamID++; // skip the G
+ eAccountType = k_EAccountTypeGameServer;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+ else if (*pchSteamID == 'C')
+ {
+ pchSteamID++; // skip the C
+ eAccountType = k_EAccountTypeContentServer;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+ else if (*pchSteamID == 'g')
+ {
+ pchSteamID++; // skip the g
+ eAccountType = k_EAccountTypeClan;
+ nInstance = 0;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+ else if (*pchSteamID == 'c')
+ {
+ pchSteamID++; // skip the c
+ eAccountType = k_EAccountTypeChat;
+ nInstance = k_EChatInstanceFlagClan;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+ else if (*pchSteamID == 'L')
+ {
+ pchSteamID++; // skip the c
+ eAccountType = k_EAccountTypeChat;
+ nInstance = k_EChatInstanceFlagLobby;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+ else if (*pchSteamID == 'T')
+ {
+ pchSteamID++; // skip the T
+ eAccountType = k_EAccountTypeChat;
+ nInstance = 0; // Anon chat
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+ else if (*pchSteamID == 'U')
+ {
+ pchSteamID++; // skip the U
+ eAccountType = k_EAccountTypeIndividual;
+ nInstance = 1;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+ else if (*pchSteamID == 'i')
+ {
+ pchSteamID++; // skip the i
+ eAccountType = k_EAccountTypeInvalid;
+ nInstance = 1;
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+
+ if ( strchr( pchSteamID, ':' ) )
+ {
+ if (*pchSteamID == '[')
+ pchSteamID++; // skip the optional [
+ sscanf( pchSteamID, "%u:%u", (uint*)&eUniverse, &nAccountID );
+ if ( eUniverse == k_EUniverseInvalid )
+ eUniverse = eDefaultUniverse;
+ }
+ else
+ {
+ uint64 unVal64 = 0;
+
+ sscanf( pchSteamID, "%llu", &unVal64 );
+ if ( unVal64 > UINT_MAX )
+ {
+ // Assume a full 64-bit Steam ID.
+ SetFromUint64( unVal64 );
+ // Catch cases where we're allowing sloppy input that we
+ // might not want to allow.
+ AssertMsg1( this->operator==( StrictID ), "Steam ID does not pass strict parsing: '%s'", pchSteamIDString );
+ return;
+ }
+ else
+ {
+ nAccountID = (uint)unVal64;
+ }
+ }
+
+ Assert( (eUniverse > k_EUniverseInvalid) && (eUniverse < k_EUniverseMax) );
+
+ InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
+
+ // Catch cases where we're allowing sloppy input that we
+ // might not want to allow.
+ AssertMsg1( this->operator==( StrictID ), "Steam ID does not pass strict parsing: '%s'", pchSteamIDString );
+}
+
+// SetFromString allows many partially-correct strings, constraining how
+// we might be able to change things in the future.
+// SetFromStringStrict requires the exact string forms that we support
+// and is preferred when the caller knows it's safe to be strict.
+// Returns whether the string parsed correctly. The ID may
+// still be invalid even if the string parsed correctly.
+// If the string didn't parse correctly the ID will always be invalid.
+bool CSteamID::SetFromStringStrict( const char *pchSteamID, EUniverse eDefaultUniverse )
+{
+ uint nAccountID = 0;
+ uint nInstance = 1;
+ uint unMaxVal = 2;
+ EUniverse eUniverse = eDefaultUniverse;
+ EAccountType eAccountType = k_EAccountTypeIndividual;
+ char chPrefix;
+ bool bBracket = false;
+ bool bValid = true;
+ uint64 unVal[3];
+ const char *pchEnd;
+
+ // Start invalid.
+ Clear();
+
+ if ( !pchSteamID )
+ {
+ return false;
+ }
+
+ if ( *pchSteamID == '[' )
+ {
+ pchSteamID++;
+ bBracket = true;
+ }
+
+ chPrefix = *pchSteamID;
+ switch( chPrefix )
+ {
+ case 'A':
+ // This is test only
+ eAccountType = k_EAccountTypeAnonGameServer;
+ unMaxVal = 3;
+ break;
+
+ case 'G':
+ eAccountType = k_EAccountTypeGameServer;
+ break;
+
+ case 'C':
+ eAccountType = k_EAccountTypeContentServer;
+ break;
+
+ case 'g':
+ eAccountType = k_EAccountTypeClan;
+ nInstance = 0;
+ break;
+
+ case 'c':
+ eAccountType = k_EAccountTypeChat;
+ nInstance = k_EChatInstanceFlagClan;
+ break;
+
+ case 'L':
+ eAccountType = k_EAccountTypeChat;
+ nInstance = k_EChatInstanceFlagLobby;
+ break;
+
+ case 'T':
+ eAccountType = k_EAccountTypeChat;
+ nInstance = 0; // Anon chat
+ break;
+
+ case 'U':
+ eAccountType = k_EAccountTypeIndividual;
+ nInstance = 1;
+ break;
+
+ case 'i':
+ eAccountType = k_EAccountTypeInvalid;
+ nInstance = 1;
+ break;
+
+ default:
+ // We're reserving other leading characters so
+ // this should only be the plain-digits case.
+ if (chPrefix < '0' || chPrefix > '9')
+ {
+ bValid = false;
+ }
+ chPrefix = 0;
+ break;
+ }
+
+ if ( chPrefix )
+ {
+ pchSteamID++; // skip the prefix
+ if (*pchSteamID == '-' || *pchSteamID == ':')
+ pchSteamID++; // skip the optional - or :
+ }
+
+ uint unIdx = 0;
+
+ for (;;)
+ {
+ pchEnd = DecimalToUint64( pchSteamID, UINT64_MAX, &unVal[unIdx] );
+ if ( !pchEnd )
+ {
+ bValid = false;
+ break;
+ }
+
+ unIdx++;
+
+ // For 'A' we can have a trailing instance, which must
+ // be the end of the string.
+ if ( *pchEnd == '(' &&
+ chPrefix == 'A' )
+ {
+ if ( unIdx > 2 )
+ {
+ // Two instance IDs provided.
+ bValid = false;
+ }
+
+ pchEnd = DecimalToUint64( pchEnd + 1, k_unSteamAccountInstanceMask, &unVal[2] );
+ if ( !pchEnd ||
+ *pchEnd != ')' )
+ {
+ bValid = false;
+ break;
+ }
+ else
+ {
+ nInstance = (uint)unVal[2];
+
+ pchEnd++;
+ if ( *pchEnd == ':' )
+ {
+ // Not expecting more values.
+ bValid = false;
+ break;
+ }
+ }
+ }
+
+ if ( *pchEnd != ':' )
+ {
+ if ( bBracket )
+ {
+ if ( *pchEnd != ']' ||
+ *(pchEnd + 1) != 0 )
+ {
+ bValid = false;
+ }
+ }
+ else if ( *pchEnd != 0 )
+ {
+ bValid = false;
+ }
+
+ break;
+ }
+
+ if ( unIdx >= unMaxVal )
+ {
+ bValid = false;
+ break;
+ }
+
+ pchSteamID = pchEnd + 1;
+ }
+
+ if ( unIdx > 2 )
+ {
+ if ( unVal[2] <= k_unSteamAccountInstanceMask )
+ {
+ nInstance = (uint)unVal[2];
+ }
+ else
+ {
+ bValid = false;
+ }
+ }
+ if ( unIdx > 1 )
+ {
+ if ( unVal[0] >= k_EUniverseInvalid &&
+ unVal[0] < k_EUniverseMax )
+ {
+ eUniverse = (EUniverse)unVal[0];
+ if ( eUniverse == k_EUniverseInvalid )
+ eUniverse = eDefaultUniverse;
+ }
+ else
+ {
+ bValid = false;
+ }
+
+ if ( unVal[1] <= k_unSteamAccountIDMask )
+ {
+ nAccountID = (uint)unVal[1];
+ }
+ else
+ {
+ bValid = false;
+ }
+ }
+ else if ( unIdx > 0 )
+ {
+ if ( unVal[0] <= k_unSteamAccountIDMask )
+ {
+ nAccountID = (uint)unVal[0];
+ }
+ else if ( !chPrefix )
+ {
+ if ( bValid )
+ {
+ SetFromUint64( unVal[0] );
+ }
+ return bValid;
+ }
+ else
+ {
+ bValid = false;
+ }
+ }
+ else
+ {
+ bValid = false;
+ }
+
+ if ( bValid )
+ {
+ if ( chPrefix == 'A' )
+ {
+ if ( nAccountID == 0 )
+ {
+ // i dont care what number you entered
+ CreateBlankAnonLogon(eUniverse);
+ return bValid;
+ }
+ }
+
+ InstancedSet( nAccountID, nInstance, eUniverse, eAccountType );
+ }
+
+ return bValid;
+}
+
+
+#if defined( INCLUDED_STEAM2_USERID_STRUCTS )
+//-----------------------------------------------------------------------------
+// Purpose: Initializes a steam ID from a Steam2 ID string
+// Input: pchSteam2ID - Steam2 ID (as a string #:#:#) to convert
+// eUniverse - universe this ID belongs to
+// Output: true if successful, false otherwise
+//-----------------------------------------------------------------------------
+bool CSteamID::SetFromSteam2String( const char *pchSteam2ID, EUniverse eUniverse )
+{
+ Assert( pchSteam2ID );
+
+ // Convert the Steam2 ID string to a Steam2 ID structure
+ TSteamGlobalUserID steam2ID;
+ steam2ID.m_SteamInstanceID = 0;
+ steam2ID.m_SteamLocalUserID.Split.High32bits = 0;
+ steam2ID.m_SteamLocalUserID.Split.Low32bits = 0;
+
+ const char *pchTSteam2ID = pchSteam2ID;
+
+ // Customer support is fond of entering steam IDs in the following form: STEAM_n:x:y
+ const char *pchOptionalLeadString = "STEAM_";
+ if ( V_strnicmp( pchSteam2ID, pchOptionalLeadString, V_strlen( pchOptionalLeadString ) ) == 0 )
+ pchTSteam2ID = pchSteam2ID + V_strlen( pchOptionalLeadString );
+
+ char cExtraCharCheck = 0;
+
+ int cFieldConverted = sscanf( pchTSteam2ID, "%hu:%u:%u%c", &steam2ID.m_SteamInstanceID,
+ &steam2ID.m_SteamLocalUserID.Split.High32bits, &steam2ID.m_SteamLocalUserID.Split.Low32bits, &cExtraCharCheck );
+
+ // Validate the conversion ... a special case is steam2 instance ID 1 which is reserved for special DoD handling
+ if ( cExtraCharCheck != 0 || cFieldConverted == EOF || cFieldConverted < 2 || ( cFieldConverted < 3 && steam2ID.m_SteamInstanceID != 1 ) )
+ return false;
+
+ // Now convert to steam ID from the Steam2 ID structure
+ SetFromSteam2( &steam2ID, eUniverse );
+ return true;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Renders the steam ID to a buffer. NOTE: for convenience of calling
+// code, this code returns a pointer to a static buffer and is NOT thread-safe.
+// Output: buffer with rendered Steam ID
+//-----------------------------------------------------------------------------
+const char * CSteamID::Render() const
+{
+ // longest length of returned string is k_cBufLen
+ // [A:%u:%u:%u]
+ // %u == 10 * 3 + 6 == 36, plus terminator == 37
+ const int k_cBufLen = 37;
+
+ const int k_cBufs = 4; // # of static bufs to use (so people can compose output with multiple calls to Render() )
+ static char rgchBuf[k_cBufs][k_cBufLen];
+ static int nBuf = 0;
+ char * pchBuf = rgchBuf[nBuf]; // get pointer to current static buf
+ nBuf ++; // use next buffer for next call to this method
+ nBuf %= k_cBufs;
+
+ if ( k_EAccountTypeAnonGameServer == m_steamid.m_comp.m_EAccountType )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[A:%u:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID, m_steamid.m_comp.m_unAccountInstance );
+ }
+ else if ( k_EAccountTypeGameServer == m_steamid.m_comp.m_EAccountType )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[G:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else if ( k_EAccountTypeMultiseat == m_steamid.m_comp.m_EAccountType )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[M:%u:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID, m_steamid.m_comp.m_unAccountInstance );
+ }
+ else if ( k_EAccountTypePending == m_steamid.m_comp.m_EAccountType )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[P:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else if ( k_EAccountTypeContentServer == m_steamid.m_comp.m_EAccountType )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[C:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else if ( k_EAccountTypeClan == m_steamid.m_comp.m_EAccountType )
+ {
+ // 'g' for "group"
+ V_snprintf( pchBuf, k_cBufLen, "[g:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else if ( k_EAccountTypeChat == m_steamid.m_comp.m_EAccountType )
+ {
+ if ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagClan )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[c:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else if ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagLobby )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[L:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else // Anon chat
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[T:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ }
+ else if ( k_EAccountTypeInvalid == m_steamid.m_comp.m_EAccountType )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[I:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else if ( k_EAccountTypeIndividual == m_steamid.m_comp.m_EAccountType )
+ {
+ if ( m_steamid.m_comp.m_unAccountInstance != k_unSteamUserDesktopInstance )
+ V_snprintf( pchBuf, k_cBufLen, "[U:%u:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID, m_steamid.m_comp.m_unAccountInstance );
+ else
+ V_snprintf( pchBuf, k_cBufLen, "[U:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else if ( k_EAccountTypeAnonUser == m_steamid.m_comp.m_EAccountType )
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[a:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ else
+ {
+ V_snprintf( pchBuf, k_cBufLen, "[i:%u:%u]", m_steamid.m_comp.m_EUniverse, m_steamid.m_comp.m_unAccountID );
+ }
+ return pchBuf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Renders the passed-in steam ID to a buffer. NOTE: for convenience of calling
+// code, this code returns a pointer to a static buffer and is NOT thread-safe.
+// Input: 64-bit representation of Steam ID to render
+// Output: buffer with rendered Steam ID
+//-----------------------------------------------------------------------------
+const char * CSteamID::Render( uint64 ulSteamID )
+{
+ CSteamID steamID( ulSteamID );
+ return steamID.Render();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: some steamIDs are for internal use only
+// This is really debug code, but we run with asserts on in retail, so ...
+//-----------------------------------------------------------------------------
+bool CSteamID::BValidExternalSteamID() const
+{
+ if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypePending )
+ return false;
+ if ( m_steamid.m_comp.m_EAccountType != k_EAccountTypeAnonGameServer && m_steamid.m_comp.m_EAccountType != k_EAccountTypeContentServer && m_steamid.m_comp.m_EAccountType != k_EAccountTypeAnonUser )
+ {
+ if ( m_steamid.m_comp.m_unAccountID == 0 && m_steamid.m_comp.m_unAccountInstance == 0 )
+ return false;
+ }
+ return true;
+}
+
+#ifdef STEAM
+//-----------------------------------------------------------------------------
+// Purpose: Returns the matching chat steamID, with the default instance of 0
+// Input: SteamID, either a Clan or a Chat type
+// Output: SteamID with account type changed to chat, and the Clan flag set.
+// If account type was not chat to start with, instance will be set to 0
+//-----------------------------------------------------------------------------
+CSteamID ChatIDFromSteamID( const CSteamID &steamID )
+{
+ if ( steamID.GetEAccountType() == k_EAccountTypeChat )
+ return steamID;
+
+ return ChatIDFromClanID( steamID );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the matching chat steamID, with the default instance of 0
+// Input: SteamID, either a Clan type or a Chat type w/ the Clan flag set
+// Output: SteamID with account type changed to clan.
+// If account type was not clan to start with, instance will be set to 0
+//-----------------------------------------------------------------------------
+CSteamID ClanIDFromSteamID( const CSteamID &steamID )
+{
+ if ( steamID.GetEAccountType() == k_EAccountTypeClan )
+ return steamID;
+
+ return ClanIDFromChatID( steamID );
+}
+
+
+// Asserts steamID type before conversion
+CSteamID ChatIDFromClanID( const CSteamID &steamIDClan )
+{
+ Assert( steamIDClan.GetEAccountType() == k_EAccountTypeClan );
+
+ return CSteamID( steamIDClan.GetAccountID(), k_EChatInstanceFlagClan, steamIDClan.GetEUniverse(), k_EAccountTypeChat );
+}
+
+
+// Asserts steamID type before conversion
+CSteamID ClanIDFromChatID( const CSteamID &steamIDChat )
+{
+ Assert( steamIDChat.GetEAccountType() == k_EAccountTypeChat );
+ Assert( k_EChatInstanceFlagClan & steamIDChat.GetUnAccountInstance() );
+
+ return CSteamID( steamIDChat.GetAccountID(), 0, steamIDChat.GetEUniverse(), k_EAccountTypeClan );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: CGameID "hidden" functions
+// move these somewhere else maybe
+//-----------------------------------------------------------------------------
+CGameID::CGameID( const char *pchGameID )
+{
+ m_ulGameID = 0;
+
+ sscanf( pchGameID, "%llu", &m_ulGameID );
+
+ switch ( m_gameID.m_nType )
+ {
+ default:
+ AssertMsg( false, "Unknown GameID type" );
+ m_ulGameID = 0;
+ break;
+ case k_EGameIDTypeApp:
+ case k_EGameIDTypeGameMod:
+ case k_EGameIDTypeShortcut:
+ case k_EGameIDTypeP2P:
+ break;
+ }
+}
+
+
+// renders this Game ID to string
+const char * CGameID::Render() const
+{
+ // longest buffer is log10(2**64) == 20 + 1 == 21
+ const int k_cBufLen = 21;
+
+ const int k_cBufs = 4; // # of static bufs to use (so people can compose output with multiple calls to Render() )
+ static char rgchBuf[k_cBufs][k_cBufLen];
+ static int nBuf = 0;
+ char * pchBuf = rgchBuf[nBuf]; // get pointer to current static buf
+ nBuf ++; // use next buffer for next call to this method
+ nBuf %= k_cBufs;
+
+ V_snprintf( pchBuf, k_cBufLen, "%llu", m_ulGameID );
+
+ return pchBuf;
+}
+
+// static method to render a uint64 representation of a Game ID to a string
+const char * CGameID::Render( uint64 ulGameID )
+{
+ CGameID nGameID( ulGameID );
+ return nGameID.Render();
+}
+#endif
diff --git a/gcsdk/steamextra/tier0/t0constants.h b/gcsdk/steamextra/tier0/t0constants.h
new file mode 100644
index 0000000..6c1524d
--- /dev/null
+++ b/gcsdk/steamextra/tier0/t0constants.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: declares a variety of constants
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef T0CONSTANTS_H
+#define T0CONSTANTS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// numeric constants to avoid typos with wrong number of zeros
+//-----------------------------------------------------------------------------
+const int64 k_nMillion = 1000000;
+const int64 k_nThousand = 1000;
+const int64 k_nKiloByte = 1024;
+const int64 k_nMegabyte = k_nKiloByte * k_nKiloByte;
+
+//-----------------------------------------------------------------------------
+// Timing constants
+//-----------------------------------------------------------------------------
+
+const unsigned int k_nSecondsPerHour = 60*60;
+const unsigned int k_nSecondsPerDay = k_nSecondsPerHour * 24;
+
+const int k_cSecondsPerMinute = 60;
+const int k_cSecondsPerHour = k_cSecondsPerMinute * 60;
+const int k_cSecondsPerDay = k_cSecondsPerHour * 24;
+const int k_cSecondsPerWeek = k_cSecondsPerDay * 7;
+const int k_cSecondsPerYear = k_cSecondsPerDay * 365;
+
+#endif // T0CONSTANTS_H \ No newline at end of file
diff --git a/gcsdk/steamextra/tier1/hashglobals.cpp b/gcsdk/steamextra/tier1/hashglobals.cpp
new file mode 100644
index 0000000..775e1da
--- /dev/null
+++ b/gcsdk/steamextra/tier1/hashglobals.cpp
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+
+#include "stdafx.h"
+#include "pearsonshash.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// This is a table of the values 0-255 in pseudo random order for use in our pearsons hash
+// variant implemented below
+const unsigned char g_CTHashRandomValues[256] =
+{
+ 131, 184, 146, 42, 124, 142, 226, 76, 8, 135, 215, 116, 228, 49, 144, 231,
+ 238, 25, 156, 125, 128, 87, 223, 38, 98, 122, 105, 4, 35, 180, 188, 160,
+ 179, 59, 218, 0, 192, 207, 209, 150, 227, 143, 140, 161, 73, 84, 111, 162,
+ 239, 74, 210, 195, 15, 225, 104, 221, 245, 12, 72, 47, 109, 187, 40, 178,
+ 208, 56, 190, 193, 126, 95, 33, 45, 177, 170, 186, 123, 202, 149, 60, 194,
+ 168, 102, 71, 148, 46, 121, 52, 119, 196, 247, 127, 145, 75, 79, 61, 254,
+ 9, 44, 23, 211, 18, 175, 251, 130, 203, 108, 85, 167, 29, 250, 138, 182,
+ 101, 213, 159, 92, 36, 10, 86, 32, 176, 80, 17, 134, 181, 114, 64, 165,
+ 89, 68, 6, 14, 205, 137, 117, 7, 39, 132, 26, 19, 214, 99, 166, 163,
+ 69, 174, 157, 100, 201, 118, 2, 28, 235, 236, 139, 244, 70, 20, 155, 82,
+ 51, 154, 115, 94, 93, 83, 136, 27, 198, 43, 50, 243, 183, 153, 53, 206,
+ 77, 55, 57, 3, 220, 147, 253, 110, 37, 246, 97, 13, 120, 103, 91, 169,
+ 58, 11, 133, 22, 152, 189, 222, 151, 141, 88, 224, 1, 48, 191, 249, 173,
+ 106, 113, 252, 172, 232, 66, 219, 96, 237, 21, 233, 62, 242, 54, 230, 65,
+ 78, 248, 16, 41, 31, 200, 90, 112, 255, 171, 164, 24, 199, 81, 212, 197,
+ 185, 67, 5, 234, 30, 129, 216, 63, 204, 158, 217, 229, 107, 240, 241, 34,
+};
diff --git a/gcsdk/steamextra/tier1/murmurhash3.cpp b/gcsdk/steamextra/tier1/murmurhash3.cpp
new file mode 100644
index 0000000..72fd8aa
--- /dev/null
+++ b/gcsdk/steamextra/tier1/murmurhash3.cpp
@@ -0,0 +1,74 @@
+//======= Copyright � Valve Corporation, All rights reserved. =================
+//
+// Public domain MurmurHash3 by Austin Appleby is a very solid general-purpose
+// hash with a 32-bit output. References:
+// http://code.google.com/p/smhasher/ (home of MurmurHash3)
+// https://sites.google.com/site/murmurhash/avalanche
+// http://www.strchr.com/hash_functions
+//
+//=============================================================================
+
+#include <stdafx.h>
+#include "murmurhash3.h"
+
+//-----------------------------------------------------------------------------
+
+uint32 MurmurHash3_32( const void * key, size_t len, uint32 seed, bool bCaselessStringVariant )
+{
+ const uint8 * data = (const uint8*)key;
+ const ptrdiff_t nblocks = len / 4;
+ uint32 uSourceBitwiseAndMask = 0xDFDFDFDF | ((uint32)bCaselessStringVariant - 1);
+
+ uint32 h1 = seed;
+
+ //----------
+ // body
+
+ const uint32 * blocks = (const uint32 *)(data + nblocks*4);
+
+ for(ptrdiff_t i = -nblocks; i; i++)
+ {
+ uint32 k1 = LittleDWord(blocks[i]);
+ k1 &= uSourceBitwiseAndMask;
+
+ k1 *= 0xcc9e2d51;
+ k1 = (k1 << 15) | (k1 >> 17);
+ k1 *= 0x1b873593;
+
+ h1 ^= k1;
+ h1 = (h1 << 13) | (h1 >> 19);
+ h1 = h1*5+0xe6546b64;
+ }
+
+ //----------
+ // tail
+
+ const uint8 * tail = (const uint8*)(data + nblocks*4);
+
+ uint32 k1 = 0;
+
+ switch(len & 3)
+ {
+ case 3: k1 ^= tail[2] << 16;
+ case 2: k1 ^= tail[1] << 8;
+ case 1: k1 ^= tail[0];
+ k1 &= uSourceBitwiseAndMask;
+ k1 *= 0xcc9e2d51;
+ k1 = (k1 << 15) | (k1 >> 17);
+ k1 *= 0x1b873593;
+ h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len;
+
+ h1 ^= h1 >> 16;
+ h1 *= 0x85ebca6b;
+ h1 ^= h1 >> 13;
+ h1 *= 0xc2b2ae35;
+ h1 ^= h1 >> 16;
+
+ return h1;
+}
diff --git a/gcsdk/steamextra/tier1/murmurhash3.h b/gcsdk/steamextra/tier1/murmurhash3.h
new file mode 100644
index 0000000..8f477cd
--- /dev/null
+++ b/gcsdk/steamextra/tier1/murmurhash3.h
@@ -0,0 +1,100 @@
+//======= Copyright � Valve Corporation, All rights reserved. =================
+//
+// Public domain MurmurHash3 by Austin Appleby is a very solid general-purpose
+// hash with a 32-bit output. References:
+// http://code.google.com/p/smhasher/ (home of MurmurHash3)
+// https://sites.google.com/site/murmurhash/avalanche
+// http://www.strchr.com/hash_functions
+//
+//=============================================================================
+
+#ifndef MURMURHASH3_H
+#define MURMURHASH3_H
+
+#if defined(_WIN32)
+#pragma once
+#endif
+
+uint32 MurmurHash3_32( const void *key, size_t len, uint32 seed, bool bCaselessStringVariant = false );
+
+inline uint32 MurmurHash3String( const char *pszKey, size_t len )
+{
+ return MurmurHash3_32( pszKey, len, 1047 /*anything will do for a seed*/, false );
+}
+
+inline uint32 MurmurHash3StringCaseless( const char *pszKey, size_t len )
+{
+ return MurmurHash3_32( pszKey, len, 1047 /*anything will do for a seed*/, true );
+}
+
+inline uint32 MurmurHash3String( const char *pszKey )
+{
+ return MurmurHash3String( pszKey, strlen( pszKey ) );
+}
+
+inline uint32 MurmurHash3StringCaseless( const char *pszKey )
+{
+ return MurmurHash3StringCaseless( pszKey, strlen( pszKey ) );
+}
+
+template <typename T>
+inline uint32 MurmurHash3Item( const T &item )
+{
+ return MurmurHash3_32( &item, sizeof(item), 1047 );
+}
+
+inline uint32 MurmurHash3Int( uint32 h )
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+}
+
+
+template <>
+inline uint32 MurmurHash3Item( const uint32 &item )
+{
+ return MurmurHash3Int( item );
+}
+
+template <>
+inline uint32 MurmurHash3Item( const int32 &item )
+{
+ return MurmurHash3Int( item );
+}
+
+
+template<typename T>
+struct MurmurHash3Functor
+{
+ typedef uint32 TargetType;
+ TargetType operator()(const T &key) const
+ {
+ return MurmurHash3Item( key );
+ }
+};
+
+template<>
+struct MurmurHash3Functor<char *>
+{
+ typedef uint32 TargetType;
+ TargetType operator()(const char *key) const
+ {
+ return MurmurHash3String( key );
+ }
+};
+
+template<>
+struct MurmurHash3Functor<const char *>
+{
+ typedef uint32 TargetType;
+ TargetType operator()(const char *key) const
+ {
+ return MurmurHash3String( key );
+ }
+};
+
+#endif // MURMURHASH3_H
diff --git a/gcsdk/steamextra/tier1/pearsonshash.h b/gcsdk/steamextra/tier1/pearsonshash.h
new file mode 100644
index 0000000..29da4a5
--- /dev/null
+++ b/gcsdk/steamextra/tier1/pearsonshash.h
@@ -0,0 +1,268 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: PearsonsHash.h
+//
+// This file contains implementation definitions of 'Pearson's' Hash'
+// The generic implementation is a template, plus a couple of specializations
+// for commonly used types.
+//
+// Take a look at http://en.wikipedia.org/wiki/Pearson_hashing for more info.
+//
+//=============================================================================
+
+#ifndef _PEARSONSHASH_H_
+#define _PEARSONSHASH_H_
+
+#if defined(_WIN32) || defined(_WIN64)
+#pragma once
+#endif
+
+extern const unsigned char g_CTHashRandomValues[256] ;
+
+template<typename T>
+struct PearsonsHashFunctor
+{
+ typedef uint32 TargetType ;
+ TargetType operator()(const T& unKey) const
+ {
+ // This is a pearsons hash variant that returns a maximum of 32 bits
+ size_t size = sizeof(T);
+ const uint8 * k = (const uint8 *) &unKey;
+ uint32 byte_one = 0, byte_two = 0, byte_three = 0, byte_four = 0, n;
+ while (size)
+ {
+ --size;
+ n = *k++;
+ byte_one = g_CTHashRandomValues[byte_one ^ n];
+
+ if (size)
+ {
+ --size;
+ n = *k++;
+ byte_two = g_CTHashRandomValues[byte_two ^ n];
+ }
+ else
+ break;
+
+ if (size)
+ {
+ --size;
+ n = *k++;
+ byte_three = g_CTHashRandomValues[byte_three ^ n];
+ }
+ else
+ break;
+
+ if (size)
+ {
+ --size;
+ n = *k++;
+ byte_four = g_CTHashRandomValues[byte_four ^ n];
+ }
+ else
+ break;
+ }
+
+ TargetType idx = ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
+ return ( idx );
+ }
+};
+
+//
+// We use this specialization for pointer types - it allows somebody
+// to define a specialization for some complicated type, and then use a
+// pointer to that type as a key, and have that automatically go to the
+// specialization for the complicated type !
+//
+template<typename T>
+struct PearsonsHashFunctor<T*>
+{
+ typedef uint32 TargetType ;
+ TargetType operator()(const T* key) const
+ {
+ PearsonsHashFunctor<T> functor ;
+ return functor(*key) ;
+ }
+};
+
+//
+// This functor specializes for unsigned 32 bit integers, a commonly used type in Steam.
+// It should return the exact same result as the unspecialized version on Intel Architecture machines.
+//
+template<>
+struct PearsonsHashFunctor<uint32>
+{
+ typedef uint32 TargetType ;
+ TargetType operator()(const uint32 unKey) const
+ {
+ uint32 byte_one = g_CTHashRandomValues[(unKey>>0) & 0xff];
+ uint32 byte_two = g_CTHashRandomValues[(unKey>>8) & 0xff];
+ uint32 byte_three = g_CTHashRandomValues[(unKey>>16) & 0xff];
+ uint32 byte_four = g_CTHashRandomValues[(unKey>>24)&0xff];
+ return ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
+ }
+};
+
+//
+// This functor specializes for unsigned 64 bit integers, another commonly used type in Steam.
+// It should return the exact same result as the unspecialized version on Intel Architecture machines.
+//
+template<>
+struct PearsonsHashFunctor<uint64>
+{
+ typedef uint32 TargetType ;
+ TargetType operator()(const uint64 unKey) const
+ {
+ //
+ // Note that we pull apart the 64 bits in Intel's endian order.
+ //
+ uint32 n;
+ //
+ // On Intel Machines, to make this return the exact same result as the generic version
+ // we have to go from least significant byte to most significant byte !
+ //
+ n = static_cast<uint32>((unKey >> (0)) & 0xff) ;
+ uint32 byte_one = g_CTHashRandomValues[n];
+ n = static_cast<uint32>((unKey >> (8)) & 0xff) ;
+ uint32 byte_two = g_CTHashRandomValues[n];
+ n = static_cast<uint32>((unKey >> (16)) & 0xff) ;
+ uint32 byte_three = g_CTHashRandomValues[n];
+ n = static_cast<uint32>((unKey >> (24)) & 0xff) ;
+ uint32 byte_four = g_CTHashRandomValues[n];
+ n = static_cast<uint32>((unKey >> (32)) & 0xff) ;
+ byte_one = g_CTHashRandomValues[n ^ byte_one];
+ n = static_cast<uint32>((unKey >> (8+32)) & 0xff) ;
+ byte_two = g_CTHashRandomValues[n ^ byte_two];
+ n = static_cast<uint32>((unKey >> (16+32)) & 0xff) ;
+ byte_three = g_CTHashRandomValues[n ^ byte_three];
+ n = static_cast<uint32>((unKey >> (24+32)) & 0xff) ;
+ byte_four = g_CTHashRandomValues[n ^ byte_four];
+ return ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
+ }
+};
+
+//
+// This functor specializes for C standard NULL terminated strings !
+// It is setup so that if you had a char array containing a NULL terminated string
+// and correctly sized, ie char rgch[16] = { "123456789012345" } and a
+// null terminated string i.e. char *sz = "123456789012345" these will return identical
+// results, and both include the NULL terminator in the hash calculation.
+//
+template<>
+struct PearsonsHashFunctor<char*>
+{
+ typedef uint32 TargetType ;
+ TargetType operator()(const char* szKey) const
+ {
+ const uint8 * k = (const uint8 *) szKey ;
+ uint32 byte_one = 0, byte_two = 0, byte_three = 0, byte_four = 0, n;
+ do
+ {
+ n = *k++;
+ byte_one = g_CTHashRandomValues[byte_one ^ n];
+ if (n=='\0')
+ break;
+
+ n = *k++;
+ byte_two = g_CTHashRandomValues[byte_two ^ n];
+ if (n=='\0')
+ break;
+
+ n = *k++;
+ byte_three = g_CTHashRandomValues[byte_three ^ n];
+ if (n=='\0')
+ break;
+
+ n = *k++;
+ byte_four = g_CTHashRandomValues[byte_four ^ n];
+ } while(n!='\0') ;
+
+ TargetType idx = ( byte_four << 24 ) | ( byte_three << 16 ) | ( byte_two << 8 ) | byte_one;
+ return ( idx );
+ }
+};
+
+//
+// This functor compares two objects of a particular type and returns a result
+// that follows the strcmp/memcmp.
+// If the type doesn't provide an operator== or operator< then you can provide
+// a type specific specialization to override this defualt functor !
+//
+template<typename T>
+struct ComparisonFunctor
+{
+ int operator()(const T &lhs, const T &rhs) const
+ {
+ if( lhs == rhs )
+ return 0 ;
+ else if( lhs < rhs )
+ return -1 ;
+ else
+ return 1 ;
+ }
+
+};
+
+//
+// I expect people to build Comparison specializations for full types,
+// not pointer types - this Specialization should allow the C++ compiler
+// to bind to a specialization for a particular type.
+// We do not want to compare pointers for equality, and a memcmp() may
+// not be good for a complicated type !
+//
+template<typename T>
+struct ComparisonFunctor<T*>
+{
+ int operator()(const T *lhs, const T *rhs) const
+ {
+ ComparisonFunctor<T> functor ;
+ return functor(*lhs, *rhs) ;
+ }
+};
+
+template<>
+struct ComparisonFunctor<int>
+{
+ int operator()(const int lhs, const int rhs) const
+ {
+ return lhs-rhs ;
+ }
+};
+
+template<>
+struct ComparisonFunctor<unsigned int>
+{
+ int operator()(const unsigned int lhs, const unsigned int rhs) const
+ {
+ return static_cast<int>(lhs) - static_cast<int>(rhs) ;
+ }
+};
+
+
+template<>
+struct ComparisonFunctor<uint64>
+{
+ int operator()(const uint64 lhs, const uint64 rhs) const
+ {
+ if( lhs < rhs )
+ return -1 ;
+ else if( lhs == rhs )
+ return 0 ;
+ else
+ return 1 ;
+ }
+};
+
+template<>
+struct ComparisonFunctor<char*>
+{
+ int operator()(const char * lhs, const char* rhs) const
+ {
+ return Q_strcmp(lhs, rhs) ;
+ }
+};
+
+
+#endif // _PEARSONSHASH_H_
+
+
diff --git a/gcsdk/steamextra/tier1/tsmempool.cpp b/gcsdk/steamextra/tier1/tsmempool.cpp
new file mode 100644
index 0000000..71b0f5b
--- /dev/null
+++ b/gcsdk/steamextra/tier1/tsmempool.cpp
@@ -0,0 +1,255 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose:
+//=============================================================================
+
+
+//#include "pch_vstdlib.h"
+
+#include "stdafx.h"
+#include "tier0/tslist.h"
+#include "tier0/t0constants.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static const uint k_cubBytesAllocatedToConsiderFreeingMemory = 5 * k_nMegabyte;
+static const int k_cBlocksAllocatedToConsiderFreeingMemory = 10;
+
+typedef TSLNodeBase_t FreeListItem_t;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CThreadSafeMemoryPool::CThreadSafeMemoryPool( int blockSize, int numElements, int growMode )
+{
+ m_ptslistFreeBlocks = new CTSListBase;
+
+ // round up to the nearest 8-byte boundary
+ if ( blockSize % TSLIST_NODE_ALIGNMENT != 0 )
+ {
+ blockSize += TSLIST_NODE_ALIGNMENT - (blockSize % TSLIST_NODE_ALIGNMENT);
+ }
+ Assert( blockSize % TSLIST_NODE_ALIGNMENT == 0 );
+ Assert( blockSize > sizeof(FreeListItem_t) );
+ m_nGrowMode = growMode;
+ m_cubBlockSize = blockSize;
+ m_nGrowSize = numElements;
+ m_cubAllocated = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees the memory contained in the mempool
+//-----------------------------------------------------------------------------
+CThreadSafeMemoryPool::~CThreadSafeMemoryPool()
+{
+ AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
+ FOR_EACH_VEC( m_vecBlockSets, i )
+ {
+ _aligned_free( m_vecBlockSets[i].m_pubBlockSet );
+ }
+
+ delete m_ptslistFreeBlocks;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees everything
+//-----------------------------------------------------------------------------
+void CThreadSafeMemoryPool::Clear()
+{
+ AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
+ ClearNoLock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees everything
+//-----------------------------------------------------------------------------
+void CThreadSafeMemoryPool::ClearNoLock()
+{
+ FOR_EACH_VEC( m_vecBlockSets, i )
+ {
+ _aligned_free( m_vecBlockSets[i].m_pubBlockSet );
+ }
+ m_ptslistFreeBlocks->Detach();
+ m_cubAllocated = 0;
+ m_cBlocksInUse = 0;
+ m_vecBlockSets.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Allocates a single block of memory from the pool.
+//-----------------------------------------------------------------------------
+void *CThreadSafeMemoryPool::Alloc()
+{
+ return Alloc( m_cubBlockSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Allocates a single block of memory from the pool.
+//-----------------------------------------------------------------------------
+void *CThreadSafeMemoryPool::Alloc( unsigned int amount )
+{
+ // loop attempting to get memory
+ // there appears to be a case where memory corruption can get this into an infinite loop
+ // normally 1 or 2 attempts are necessary to get a block, so if we hit 1000 we know something is wrong
+ int cAttempts = 1000;
+ while ( --cAttempts )
+ {
+ // pull first from the free list
+ m_threadRWLock.LockForRead();
+ FreeListItem_t *pFreeListItem = m_ptslistFreeBlocks->Pop();
+ if ( pFreeListItem )
+ {
+ m_threadRWLock.UnlockRead();
+ m_cBlocksInUse++;
+ return (void *)pFreeListItem;
+ }
+ m_threadRWLock.UnlockRead();
+
+ // no free items, add a new block
+
+ // switch from a read lock to a write lock
+ AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
+
+ // another thread may have allocated memory; try the free list again if so
+ if ( m_ptslistFreeBlocks->Count() > 0 )
+ continue;
+
+ size_t cubBlob = m_nGrowSize * m_cubBlockSize;
+ if ( m_nGrowMode == GROW_FAST )
+ {
+ cubBlob *= (m_vecBlockSets.Count() + 1);
+ }
+
+ // don't grow if we're told not to
+ if ( m_nGrowMode == GROW_NONE && m_vecBlockSets.Count() == 1 )
+ return NULL;
+
+ // allocate, but we can fail
+ byte *pBlobBase = (byte *)MemAlloc_AllocAligned( cubBlob, TSLIST_NODE_ALIGNMENT /*, (m_nGrowMode == GROW_TIL_YOU_CANT)*/ );
+ if ( !pBlobBase )
+ return NULL;
+
+ byte *pBlobEnd = pBlobBase + cubBlob;
+ // add all the items to the pool
+ for ( byte *pBlob = pBlobBase; pBlob < pBlobEnd; pBlob += m_cubBlockSize )
+ {
+ m_ptslistFreeBlocks->Push( (FreeListItem_t *)pBlob );
+ }
+
+ m_cubAllocated += cubBlob;
+ BlockSet_t blockSet = { pBlobBase, cubBlob };
+ m_vecBlockSets.AddToTail( blockSet );
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees a block of memory
+//-----------------------------------------------------------------------------
+void CThreadSafeMemoryPool::Free( void *pMem )
+{
+ Free( pMem, m_cubBlockSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees a block of memory
+//-----------------------------------------------------------------------------
+void CThreadSafeMemoryPool::Free( void *pMem, int cubAlloc )
+{
+ m_threadRWLock.LockForRead();
+
+ // push the item back onto the free list
+ m_ptslistFreeBlocks->Push( (FreeListItem_t *)pMem );
+ m_cBlocksInUse--;
+
+ m_threadRWLock.UnlockRead();
+
+ // if we're completely free, and have too much memory allocated, free some
+ if ( m_cBlocksInUse == 0
+ && m_cubAllocated >= k_cubBytesAllocatedToConsiderFreeingMemory
+ && m_vecBlockSets.Count() >= k_cBlocksAllocatedToConsiderFreeingMemory )
+ {
+ AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
+
+ // check again nothing is in use
+ if ( m_cBlocksInUse == 0 )
+ {
+ // free all the blocks
+ ClearNoLock();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: display
+//-----------------------------------------------------------------------------
+void CThreadSafeMemoryPool::PrintStats()
+{
+ AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
+ int cBlocksInUse = m_cBlocksInUse;
+ Msg( "Block size: %-11s Alloc'd: %8d Num blobs: %5d (%s)\n", Q_pretifymem( m_cubBlockSize, 2, true ),
+ cBlocksInUse, m_vecBlockSets.Count(), Q_pretifymem( m_cubAllocated, 2, true ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+size_t CThreadSafeMemoryPool::CubTotalSize()
+{
+ return m_cubAllocated;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+size_t CThreadSafeMemoryPool::CubSizeInUse()
+{
+ return m_cBlocksInUse * m_cubBlockSize;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+int CThreadSafeMemoryPool::Count()
+{
+ return m_cBlocksInUse;
+}
+
+
+#ifdef DBGFLAG_VALIDATE
+//-----------------------------------------------------------------------------
+// Purpose: Run a global validation pass on all of our data structures and memory
+// allocations.
+// Input: validator - Our global validator object
+// pchName - Our name (typically a member var in our container)
+//-----------------------------------------------------------------------------
+void CThreadSafeMemoryPool::Validate( CValidator &validator, const char *pchName )
+{
+ AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
+ VALIDATE_SCOPE();
+ FOR_EACH_VEC( m_vecBlockSets, i )
+ {
+ validator.ClaimMemory( MemAlloc_Unalign( m_vecBlockSets[i].m_pubBlockSet ) );
+ }
+ ValidateObj( m_vecBlockSets );
+ validator.ClaimMemory( MemAlloc_Unalign( m_ptslistFreeBlocks ) );
+}
+#endif // DBGFLAG_VALIDATE
diff --git a/gcsdk/steamextra/tier1/tsmempool.h b/gcsdk/steamextra/tier1/tsmempool.h
new file mode 100644
index 0000000..402681c
--- /dev/null
+++ b/gcsdk/steamextra/tier1/tsmempool.h
@@ -0,0 +1,170 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef TSMEMPOOL_H
+#define TSMEMPOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#undef new
+
+//-----------------------------------------------------------------------------
+// Purpose: Optimized pool memory allocator
+//-----------------------------------------------------------------------------
+class CThreadSafeMemoryPool
+{
+public:
+ enum
+ {
+ GROW_NONE=0, // Don't allow new blobs.
+ GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates get larger and larger each time it allocates one).
+ GROW_SLOW=2, // New blob size is numElements.
+ GROW_TIL_YOU_CANT=3 // GROW_SLOW til alloc fails - then STOP and dont assert!
+ };
+
+ CThreadSafeMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST );
+ ~CThreadSafeMemoryPool();
+
+ void *Alloc(); // Allocate the element size you specified in the constructor.
+ void *Alloc( unsigned int cubAlloc );
+ void Free( void *pMem );
+ void Free( void *pMem, int cubAlloc );
+
+ // Frees everything
+ void Clear();
+
+ // display
+ void PrintStats();
+ size_t CubTotalSize();
+ size_t CubSizeInUse();
+ int Count();
+
+ static void * operator new( size_t size )
+ {
+ CThreadSafeMemoryPool *pNode = (CThreadSafeMemoryPool *)MemAlloc_AllocAligned( size, 8, __FILE__, __LINE__
+#ifdef STEAM
+ , true // new operator
+#endif
+ );
+ return pNode;
+ }
+
+ static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine )
+ {
+ CThreadSafeMemoryPool *pNode = (CThreadSafeMemoryPool *)MemAlloc_AllocAligned( size, 8, pFileName, nLine
+#ifdef STEAM
+ , true // new operator
+#endif
+ );
+ return pNode;
+ }
+
+ static void operator delete( void *p)
+ {
+ MemAlloc_FreeAligned( p
+#ifdef STEAM
+ , true // new operator
+#endif
+ );
+ }
+
+ static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine )
+ {
+ MemAlloc_FreeAligned( p
+#ifdef STEAM
+ , true // new operator
+#endif
+ );
+ }
+
+#ifdef DBGFLAG_VALIDATE
+ void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures
+#endif // DBGFLAG_VALIDATE
+
+private:
+ // These ain't gonna work
+ static void * operator new[] ( size_t size );
+ static void operator delete [] ( void *p);
+
+ // CThreadSpinRWLock needs 8 byte alignment to work but we new() CThreadSafeMemoryPool
+ // so simply place it at the start of the class to make sure it fits on the 8-byte boundary
+ CThreadSpinRWLock m_threadRWLock;
+
+ int m_nGrowMode;
+ int m_cubBlockSize;
+ int m_nGrowSize;
+
+ void ClearNoLock();
+
+ CInterlockedInt m_cBlocksInUse;
+ size_t m_cubAllocated;
+
+ struct BlockSet_t
+ {
+ byte *m_pubBlockSet;
+ size_t m_cubAllocated;
+ };
+ CUtlVector<BlockSet_t> m_vecBlockSets;
+
+ class CTSListBase *m_ptslistFreeBlocks;
+};
+
+
+//-----------------------------------------------------------------------------
+// Wrapper macro to make an allocator that returns particular typed allocations
+// and construction and destruction of objects.
+//-----------------------------------------------------------------------------
+template< class T >
+class CThreadSafeClassMemoryPool : public CThreadSafeMemoryPool
+{
+public:
+ CThreadSafeClassMemoryPool(int numElements, int growMode = GROW_FAST) :
+ CThreadSafeMemoryPool( sizeof(T), numElements, growMode ) {}
+
+ T* Alloc();
+ void Free( T *pMem );
+};
+
+
+template< class T >
+T* CThreadSafeClassMemoryPool<T>::Alloc()
+{
+ T *pRet = (T*)CThreadSafeMemoryPool::Alloc();
+ if ( pRet )
+ {
+ Construct( pRet );
+ }
+ return pRet;
+}
+
+
+template< class T >
+void CThreadSafeClassMemoryPool<T>::Free(T *pMem)
+{
+ if ( pMem )
+ {
+ Destruct( pMem );
+ }
+
+ CThreadSafeMemoryPool::Free( pMem );
+}
+
+
+#endif // TSMEMPOOL_H
diff --git a/gcsdk/steamextra/tier1/tsmultimempool.cpp b/gcsdk/steamextra/tier1/tsmultimempool.cpp
new file mode 100644
index 0000000..86a8b50
--- /dev/null
+++ b/gcsdk/steamextra/tier1/tsmultimempool.cpp
@@ -0,0 +1,383 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include <stdafx.h>
+#include "tier0/t0constants.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static const int k_cubMemBlockPrefixSize = sizeof(uint32);
+
+#define ALLOCSIZE_TO_LOOKUP( cubAlloc ) ( (cubAlloc - 1) >> 5 )
+#define LOOKUP_TO_ALLOCSIZE( iLookup ) ( (iLookup << 5) + 1 )
+
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor, the sizes in pMemPoolConfig must be in ascending order
+//-----------------------------------------------------------------------------
+CThreadSafeMultiMemoryPool::CThreadSafeMultiMemoryPool( const MemPoolConfig_t *pMemPoolConfig, int cnMemPoolConfig, int nGrowMode /*= GROW_FAST*/ )
+{
+ m_cubReallocedTotal = 0;
+ m_MapRawAllocation.SetLessFunc( DefLessFunc( void * ) );
+
+ for ( int iMemPoolConfig = 0; iMemPoolConfig < cnMemPoolConfig; iMemPoolConfig++ )
+ {
+ MemPoolRecord_t memPoolRecord;
+ // verify that the mem pool sizes are in ascending order
+ Assert( iMemPoolConfig == 0 || ( iMemPoolConfig > 0 && pMemPoolConfig[ iMemPoolConfig - 1 ].m_cubBlockSize < pMemPoolConfig[ iMemPoolConfig].m_cubBlockSize ) );
+ AssertMsg( pMemPoolConfig[ iMemPoolConfig].m_cubBlockSize % 32 == 0, "Mempools sizes must be multiples of 32" );
+ // add an int to the block size so we can note the alloc size
+ memPoolRecord.m_pMemPool = new CThreadSafeMemoryPool( pMemPoolConfig[ iMemPoolConfig ].m_cubBlockSize + k_cubMemBlockPrefixSize,
+ pMemPoolConfig[ iMemPoolConfig ].m_cubDefaultPoolSize, nGrowMode );
+ Assert( memPoolRecord.m_pMemPool );
+ memPoolRecord.m_nBlockSize = pMemPoolConfig[ iMemPoolConfig ].m_cubBlockSize;
+ m_VecMemPool.AddToTail( memPoolRecord );
+
+ // update the largest blocksize
+ m_nBlockSizeMax = MAX( m_nBlockSizeMax, memPoolRecord.m_nBlockSize );
+ }
+
+ // build the lookup table
+ int nLookupMax = m_nBlockSizeMax >> 5;
+ m_VecMemPoolLookup.AddMultipleToTail( nLookupMax );
+ for ( int i = 0; i < nLookupMax; i++ )
+ {
+ uint32 cubAllocSize = LOOKUP_TO_ALLOCSIZE( i );
+ for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ if ( m_VecMemPool[iMemPool].m_nBlockSize >= cubAllocSize )
+ {
+ m_VecMemPoolLookup[i] = &m_VecMemPool[iMemPool];
+ break;
+ }
+ }
+ }
+
+#if defined(_DEBUG)
+ // validate the lookup table
+ for ( int i = 1; i < (int)m_nBlockSizeMax; i++ )
+ {
+ for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ if ( (int)m_VecMemPool[iMemPool].m_nBlockSize >= i )
+ {
+ AssertMsg( m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP(i)] == &m_VecMemPool[iMemPool], "Invalid mempool block size, can't generate lookup table" );
+ break;
+ }
+ }
+ }
+#endif // _DEBUG
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CThreadSafeMultiMemoryPool::~CThreadSafeMultiMemoryPool()
+{
+ AUTO_LOCK( m_mutexRawAllocations );
+
+ for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool ++ )
+ {
+ delete m_VecMemPool[iMemPool].m_pMemPool;
+ }
+
+ FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
+ {
+ FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Allocates a block of memory at of least nAllocSize bytes
+// Input : nAllocSize - number of bytes to alloc
+// Output : pointer to memory alloc'd, NULL on error
+//-----------------------------------------------------------------------------
+void *CThreadSafeMultiMemoryPool::Alloc( uint32 cubAllocSize )
+{
+ if ( cubAllocSize == 0 )
+ return NULL;
+
+ if ( cubAllocSize <= m_nBlockSizeMax )
+ {
+ MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubAllocSize )];
+ void *pvMem = pMemPoolRecord->m_pMemPool->Alloc( cubAllocSize + k_cubMemBlockPrefixSize );
+ *(uint32 *)pvMem = cubAllocSize;
+ return ( (char *)pvMem + k_cubMemBlockPrefixSize );
+ }
+
+
+ // can't fit in our mem pools, alloc it in our one off buffer
+ RawAllocation_t rawAllocation;
+ rawAllocation.m_nBlockSize = cubAllocSize;
+ rawAllocation.m_pvMem = PvAlloc( cubAllocSize + k_cubMemBlockPrefixSize );
+ if ( !rawAllocation.m_pvMem )
+ {
+ return NULL;
+ }
+ *(uint32 *)rawAllocation.m_pvMem = rawAllocation.m_nBlockSize;
+ AUTO_LOCK( m_mutexRawAllocations );
+ m_MapRawAllocation.Insert( rawAllocation.m_pvMem, rawAllocation );
+ return ( (char *)rawAllocation.m_pvMem + k_cubMemBlockPrefixSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Free a previously alloc'd block
+// Input : pMem - memory to free
+//-----------------------------------------------------------------------------
+void CThreadSafeMultiMemoryPool::Free( void *pvMem )
+{
+ if ( !pvMem )
+ return;
+
+ uint32 cubAllocSize = *( (uint32 *)pvMem - 1 );
+
+ if ( cubAllocSize <= m_nBlockSizeMax )
+ {
+ MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubAllocSize )];
+ pMemPoolRecord->m_pMemPool->Free( (char *)pvMem - k_cubMemBlockPrefixSize, cubAllocSize + k_cubMemBlockPrefixSize );
+ return;
+ }
+
+ AUTO_LOCK( m_mutexRawAllocations );
+
+ // must have been alloc'd from the raw heap, find it in map
+ void *pvAllocedMem = (char *)pvMem - k_cubMemBlockPrefixSize;
+ int iRawAllocation = m_MapRawAllocation.Find( pvAllocedMem );
+ if ( m_MapRawAllocation.InvalidIndex() == iRawAllocation )
+ {
+ AssertMsg3( false, "CThreadSafeMultiMemoryPool::Free: raw allocation %p (original alloc: %p, %d bytes) not found in allocation map",
+ pvMem, pvAllocedMem, cubAllocSize );
+ return;
+
+ }
+
+ FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem );
+ m_MapRawAllocation.RemoveAt( iRawAllocation);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the size alloc'd for this block
+// Input : pMem - memory to report
+// Output : size in bytes of this memory
+//-----------------------------------------------------------------------------
+int CThreadSafeMultiMemoryPool::CubAllocSize(void *pvMem)
+{
+ if ( !pvMem )
+ {
+ return -1;
+ }
+
+ return *(((uint32 *)pvMem) -1);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees all previously alloc'd memory
+//-----------------------------------------------------------------------------
+void CThreadSafeMultiMemoryPool::Clear()
+{
+ AUTO_LOCK( m_mutexRawAllocations );
+
+ for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ m_VecMemPool[iMemPool].m_pMemPool->Clear();
+ }
+
+ FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
+ {
+ FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem );
+ }
+ m_MapRawAllocation.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: print to the console info about our storage
+//-----------------------------------------------------------------------------
+void CThreadSafeMultiMemoryPool::PrintStats()
+{
+ for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ m_VecMemPool[iMemPool].m_pMemPool->PrintStats();
+ }
+ int cubRawBytesAllocd = 0;
+ AUTO_LOCK( m_mutexRawAllocations );
+ FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
+ {
+ cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize;
+ }
+ Msg( "Raw bytes alloc'd: %s\n", Q_pretifymem( cubRawBytesAllocd, 2, true ) );
+ Msg( "Cumulative bytes re-alloced: %s\n", Q_pretifymem( m_cubReallocedTotal, 2, true ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: return the total mem alloced by this pool in MB
+//-----------------------------------------------------------------------------
+int CThreadSafeMultiMemoryPool::CMBPoolSize() const
+{
+ uint64 cubRawBytesAllocd = 0;
+ for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ cubRawBytesAllocd += ( m_VecMemPool[iMemPool].m_pMemPool->CubTotalSize() );
+ }
+ AUTO_LOCK( m_mutexRawAllocations );
+ FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
+ {
+ cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize;
+ }
+
+ return ( cubRawBytesAllocd / k_nMegabyte );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: return the total mem alloced by this pool in MB
+//-----------------------------------------------------------------------------
+int CThreadSafeMultiMemoryPool::CMBPoolSizeInUse() const
+{
+ uint64 cubRawBytesAllocd = 0;
+ for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ cubRawBytesAllocd += ( m_VecMemPool[iMemPool].m_pMemPool->CubSizeInUse() );
+ }
+ AUTO_LOCK( m_mutexRawAllocations );
+ FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
+ {
+ cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize;
+ }
+
+ return ( cubRawBytesAllocd / k_nMegabyte );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: return number of mempool blocks alloc'd
+//-----------------------------------------------------------------------------
+int CThreadSafeMultiMemoryPool::Count()
+{
+ int cCount = 0;
+ for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ cCount += m_VecMemPool[iMemPool].m_pMemPool->Count();
+ }
+ return cCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: reallocate an existing block of memory to a new size (and copy the data
+// Input: pvMem - a pointer to the existing memory
+// cubAlloc - number of bytes to alloc
+// Output: returns a pointer to the memory allocated (NULL on error)
+//-----------------------------------------------------------------------------
+void *CThreadSafeMultiMemoryPool::ReAlloc( void *pvMem, uint32 cubAlloc )
+{
+ uint32 cubOldAlloc = CubAllocSize(pvMem);
+ if ( pvMem && cubAlloc <= cubOldAlloc )
+ return pvMem;
+
+ if ( cubOldAlloc > m_nBlockSizeMax )
+ {
+ AUTO_LOCK( m_mutexRawAllocations );
+ // okay, must have been alloc'd from the raw heap, search for it
+ void *pvAllocedMem = (char *)pvMem - k_cubMemBlockPrefixSize;
+ int iRawAllocation = m_MapRawAllocation.Find( pvAllocedMem );
+ if ( m_MapRawAllocation.InvalidIndex() == iRawAllocation )
+ {
+ AssertMsg3( false, "CThreadSafeMultiMemoryPool::ReAlloc: raw allocation %p (original alloc: %p, %d bytes) not found in allocation map",
+ pvMem, pvAllocedMem, cubOldAlloc );
+ return NULL;
+ }
+
+ // realloc the memory
+ void *pvNewMem = PvRealloc( pvAllocedMem, cubAlloc + k_cubMemBlockPrefixSize );
+ if ( !pvNewMem )
+ {
+ m_MapRawAllocation.RemoveAt( iRawAllocation );
+ return NULL;
+ }
+
+ // update our tracking
+ *(uint32 *)pvNewMem = cubAlloc;
+ if ( pvAllocedMem == pvNewMem )
+ {
+ // if pointer is the same, use the same map entry with the same key (the pointer given to caller)
+ m_MapRawAllocation[iRawAllocation].m_pvMem = pvNewMem;
+ m_MapRawAllocation[iRawAllocation].m_nBlockSize = cubAlloc;
+ }
+ else
+ {
+ // if pointer changed, need to remove the old entry and re-insert with new key
+ m_MapRawAllocation.RemoveAt( iRawAllocation );
+ RawAllocation_t rawAllocation;
+ rawAllocation.m_pvMem = pvNewMem;
+ rawAllocation.m_nBlockSize = cubAlloc;
+ m_MapRawAllocation.Insert( rawAllocation.m_pvMem, rawAllocation );
+ }
+ return ( (char *)pvNewMem + k_cubMemBlockPrefixSize );
+ }
+ else
+ {
+ // see if we can stay in the same block
+ MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubOldAlloc )];
+ if ( cubAlloc <= pMemPoolRecord->m_nBlockSize )
+ {
+ // re-assign the size
+ *((uint32 *)pvMem - 1) = cubAlloc;
+ return pvMem;
+ }
+
+ void *pvNewMem = Alloc( cubAlloc );
+ if ( !pvNewMem )
+ {
+ return NULL;
+ }
+ m_cubReallocedTotal += cubOldAlloc;
+ Q_memcpy( pvNewMem, pvMem, cubOldAlloc );
+ Free( pvMem ); // now free the old memory buffer we had
+ return pvNewMem;
+ }
+}
+
+
+#ifdef DBGFLAG_VALIDATE
+//-----------------------------------------------------------------------------
+// Purpose: Ensure that all of our internal structures are consistent, and
+// account for all memory that we've allocated.
+// Input: validator - Our global validator object
+// pchName - Our name (typically a member var in our container)
+//-----------------------------------------------------------------------------
+void CThreadSafeMultiMemoryPool::Validate( CValidator &validator, const char *pchName )
+{
+ validator.Push( "CThreadSafeMultiMemoryPool", this, pchName );
+
+ ValidateObj( m_VecMemPool );
+ for( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
+ {
+ validator.ClaimMemory_Aligned( m_VecMemPool[iMemPool].m_pMemPool );
+ m_VecMemPool[iMemPool].m_pMemPool->Validate( validator, "m_VecMemPool[iMemPool].m_pMemPool" );
+ }
+
+ AUTO_LOCK( m_mutexRawAllocations );
+ ValidateObj( m_MapRawAllocation );
+ FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
+ {
+ validator.ClaimMemory( m_MapRawAllocation[iRawAllocation].m_pvMem );
+ }
+
+ ValidateObj( m_VecMemPoolLookup );
+
+ validator.Pop();
+}
+#endif // DBGFLAG_VALIDATE
+
diff --git a/gcsdk/steamextra/tier1/tsmultimempool.h b/gcsdk/steamextra/tier1/tsmultimempool.h
new file mode 100644
index 0000000..860e9df
--- /dev/null
+++ b/gcsdk/steamextra/tier1/tsmultimempool.h
@@ -0,0 +1,97 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================
+
+#ifndef TSMULTIMEMPOOL_H
+#define TSMULTIMEMPOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier1/utlmap.h"
+#include "tier1/mempool.h"
+#include "tier1/tsmempool.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: A container of a range of mem pool sizes (for network buffers for example)
+// and a raw alloc capability (for sizes greater than any contained mem pool).
+//-----------------------------------------------------------------------------
+class CThreadSafeMultiMemoryPool
+{
+public:
+ struct MemPoolConfig_t
+ {
+ uint32 m_cubBlockSize;
+ uint32 m_cubDefaultPoolSize;
+ };
+
+ CThreadSafeMultiMemoryPool( const MemPoolConfig_t *pnBlock, int cnMemPoolConfig, int nGrowMode = UTLMEMORYPOOL_GROW_FAST );
+ ~CThreadSafeMultiMemoryPool();
+
+ // Allocate a block of at least nAllocSize bytes
+ void* Alloc( uint32 cubAlloc );
+ // Free a previously alloc'd block
+ void Free(void *pvMem);
+ // ReAllocate a previously allocated block to a new size
+ void* ReAlloc( void *pvMem, uint32 cubAlloc );
+
+ // Frees everything
+ void Clear();
+
+ // alloc size for this bit of alloc'd memory
+ int CubAllocSize( void *pvMem );
+ // prints details about our contained memory
+ void PrintStats();
+
+ // total number of alloc'd elements
+ int Count();
+
+ // Return the total size in MB allocated for this pool
+ int CMBPoolSize() const;
+ // Return the amount of memory in use
+ int CMBPoolSizeInUse() const;
+
+#ifdef DBGFLAG_VALIDATE
+ void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures
+#endif // DBGFLAG_VALIDATE
+
+private:
+ struct MemPoolRecord_t
+ {
+ CThreadSafeMemoryPool *m_pMemPool;
+ uint32 m_nBlockSize;
+ };
+
+ CUtlVector<MemPoolRecord_t> m_VecMemPool; // stores our list of mem pools
+
+ uint32 m_nBlockSizeMax;
+ CUtlVector<MemPoolRecord_t *> m_VecMemPoolLookup; // quick lookup table of mempools
+
+ struct RawAllocation_t
+ {
+ void *m_pvMem;
+ uint32 m_nBlockSize;
+ };
+ CUtlMap<void *,RawAllocation_t,int> m_MapRawAllocation; // stores our list of raw alloc'd mem
+ CThreadFastMutex m_mutexRawAllocations;
+
+ uint32 m_cubReallocedTotal;
+};
+
+
+#endif // TSMULTIMEMPOOL_H
diff --git a/gcsdk/steamextra/tier1/utlhashmaplarge.h b/gcsdk/steamextra/tier1/utlhashmaplarge.h
new file mode 100644
index 0000000..5525930
--- /dev/null
+++ b/gcsdk/steamextra/tier1/utlhashmaplarge.h
@@ -0,0 +1,693 @@
+//========= Copyright Valve Corporation, All rights reserved. =================//
+//
+// Purpose: index-based hash map container well suited for large and growing
+// datasets. It uses less memory than other hash maps and incrementally
+// rehashes to reduce reallocation spikes.
+//
+//=============================================================================//
+
+#ifndef UTLHASHMAPLARGE_H
+#define UTLHASHMAPLARGE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "bitvec.h"
+#include "tier1/murmurhash3.h"
+
+// fast mod for power of 2 numbers
+namespace basetypes
+{
+template <class T>
+inline bool IsPowerOf2(T n)
+{
+ return n > 0 && (n & (n-1)) == 0;
+}
+
+template <class T1, class T2>
+inline T2 ModPowerOf2(T1 a, T2 b)
+{
+ return T2(a) & (b-1);
+}
+}
+
+// default comparison operator
+template <typename T>
+class CDefEquals
+{
+public:
+ CDefEquals() {}
+ CDefEquals( int i ) {}
+ inline bool operator()( const T &lhs, const T &rhs ) const { return ( lhs == rhs ); }
+ inline bool operator!() const { return false; }
+};
+
+
+// Specialization to compare pointers
+template <typename T>
+class CDefEquals<T*>
+{
+public:
+ CDefEquals() {}
+ CDefEquals( int i ) {}
+ inline bool operator()( const T *lhs, const T *rhs ) const
+ {
+ if ( lhs == rhs )
+ return true;
+ else if ( NULL == lhs || NULL == rhs )
+ return false;
+ else
+ return ( *lhs == *rhs );
+ }
+ inline bool operator!() const { return false; }
+};
+
+
+// Hash specialization for CUtlStrings
+template<>
+struct MurmurHash3Functor<CUtlString>
+{
+ typedef uint32 TargetType ;
+ TargetType operator()(const CUtlString &strKey) const
+ {
+ return MurmurHash3Functor<const char*>()( strKey.String() );
+ }
+};
+
+//hash 3 function for a general case sensitive string compares
+struct MurmurHash3ConstCharPtr
+{
+ typedef uint32 TargetType ;
+ TargetType operator()( const char* pszKey ) const { return MurmurHash3Functor<const char*>()( pszKey ); }
+};
+struct CaseSensitiveStrEquals
+{
+ bool operator()( const char* pszLhs, const char* pszRhs ) const { return strcmp( pszLhs, pszRhs ) == 0; }
+};
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: An associative container. Pretty much identical to CUtlMap without the ability to walk in-order
+// This container is well suited for large and growing datasets. It uses less
+// memory than other hash maps and incrementally rehashes to reduce reallocation spikes.
+// However, it is slower (by about 20%) than CUtlHashTable
+//
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L = CDefEquals<K>, typename H = MurmurHash3Functor<K> >
+class CUtlHashMapLarge
+{
+public:
+ // This enum exists so that FOR_EACH_MAP and FOR_EACH_MAP_FAST cannot accidentally
+ // be used on a type that is not a CUtlMap. If the code compiles then all is well.
+ // The check for IsUtlMap being true should be free.
+ // Using an enum rather than a static const bool ensures that this trick works even
+ // with optimizations disabled on gcc.
+ enum CompileTimeCheck
+ {
+ IsUtlMap = 1
+ };
+
+ typedef K KeyType_t;
+ typedef T ElemType_t;
+ typedef int IndexType_t;
+ typedef L EqualityFunc_t;
+ typedef H HashFunc_t;
+
+ CUtlHashMapLarge()
+ {
+ m_cElements = 0;
+ m_nMaxElement = 0;
+ m_nMinRehashedBucket = InvalidIndex();
+ m_nMaxRehashedBucket = InvalidIndex();
+ m_iNodeFreeListHead = InvalidIndex();
+ }
+
+ CUtlHashMapLarge( int cElementsExpected )
+ {
+ m_cElements = 0;
+ m_nMaxElement = 0;
+ m_nMinRehashedBucket = InvalidIndex();
+ m_nMaxRehashedBucket = InvalidIndex();
+ m_iNodeFreeListHead = InvalidIndex();
+ EnsureCapacity( cElementsExpected );
+ }
+
+ ~CUtlHashMapLarge()
+ {
+ RemoveAll();
+ }
+
+ // gets particular elements
+ ElemType_t & Element( IndexType_t i ) { return m_memNodes.Element( i ).m_elem; }
+ const ElemType_t & Element( IndexType_t i ) const { return m_memNodes.Element( i ).m_elem; }
+ ElemType_t & operator[]( IndexType_t i ) { return m_memNodes.Element( i ).m_elem; }
+ const ElemType_t & operator[]( IndexType_t i ) const { return m_memNodes.Element( i ).m_elem; }
+ KeyType_t & Key( IndexType_t i ) { return m_memNodes.Element( i ).m_key; }
+ const KeyType_t & Key( IndexType_t i ) const { return m_memNodes.Element( i ).m_key; }
+
+ // Num elements
+ IndexType_t Count() const { return m_cElements; }
+
+ // Max "size" of the vector
+ IndexType_t MaxElement() const { return m_nMaxElement; }
+
+ // Checks if a node is valid and in the map
+ bool IsValidIndex( IndexType_t i ) const { return i >= 0 && i < m_nMaxElement && !IsFreeNodeID( m_memNodes[i].m_iNextNode ); }
+
+ // Invalid index
+ static IndexType_t InvalidIndex() { return -1; }
+
+ // Insert method
+ IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_UpdateExisting ); }
+ IndexType_t Insert( const KeyType_t &key ) { return InsertInternal( key, ElemType_t(), eInsert_UpdateExisting ); }
+ IndexType_t InsertWithDupes( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_CreateDupes ); }
+ IndexType_t FindOrInsert( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_LeaveExisting ); }
+ IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_UpdateExisting ); }
+
+
+ // Finds an element
+ IndexType_t Find( const KeyType_t &key ) const;
+
+ // has an element
+ bool HasElement( const KeyType_t &key ) const
+ {
+ return Find( key ) != InvalidIndex();
+ }
+
+ void EnsureCapacity( int num );
+
+ void RemoveAt( IndexType_t i );
+ bool Remove( const KeyType_t &key )
+ {
+ int iMap = Find( key );
+ if ( iMap != InvalidIndex() )
+ {
+ RemoveAt( iMap );
+ return true;
+ }
+ return false;
+ }
+ void RemoveAll();
+ void Purge();
+ void PurgeAndDeleteElements();
+
+ void Swap( CUtlHashMapLarge<K,T,L,H> &rhs )
+ {
+ m_vecHashBuckets.Swap( rhs.m_vecHashBuckets );
+ V_swap( m_bitsMigratedBuckets, rhs.m_bitsMigratedBuckets );
+ m_memNodes.Swap( rhs.m_memNodes );
+ V_swap( m_iNodeFreeListHead, rhs.m_iNodeFreeListHead );
+ V_swap( m_cElements, rhs.m_cElements );
+ V_swap( m_nMaxElement, rhs.m_nMaxElement );
+ V_swap( m_nMinRehashedBucket, rhs.m_nMinRehashedBucket );
+ V_swap( m_nMaxRehashedBucket, rhs.m_nMaxRehashedBucket );
+ V_swap( m_EqualityFunc, rhs.m_EqualityFunc );
+ V_swap( m_HashFunc, rhs.m_HashFunc );
+ }
+
+private:
+ enum EInsertPolicy { eInsert_UpdateExisting, eInsert_LeaveExisting, eInsert_CreateDupes };
+ IndexType_t InsertInternal( const KeyType_t &key, const ElemType_t &insert, EInsertPolicy ePolicy );
+
+ inline IndexType_t FreeNodeIDToIndex( IndexType_t i ) const { return (0-i)-3; }
+ inline IndexType_t FreeNodeIndexToID( IndexType_t i ) const { return (-3)-i; }
+ inline bool IsFreeNodeID( IndexType_t i ) const { return i < InvalidIndex(); }
+
+ int FindInBucket( int iBucket, const KeyType_t &key ) const;
+ int AllocNode();
+ void RehashNodesInBucket( int iBucket );
+ void LinkNodeIntoBucket( int iBucket, int iNewNode );
+ void UnlinkNodeFromBucket( int iBucket, int iNewNode );
+ bool RemoveNodeFromBucket( int iBucket, int iNodeToRemove );
+ void IncrementalRehash();
+
+ struct HashBucket_t
+ {
+ IndexType_t m_iNode;
+ };
+ CUtlVector<HashBucket_t> m_vecHashBuckets;
+
+ CLargeVarBitVec m_bitsMigratedBuckets;
+
+ struct Node_t
+ {
+ KeyType_t m_key;
+ ElemType_t m_elem;
+ int m_iNextNode;
+ };
+ CUtlMemory<Node_t> m_memNodes;
+ IndexType_t m_iNodeFreeListHead;
+
+ IndexType_t m_cElements;
+ IndexType_t m_nMaxElement;
+ IndexType_t m_nMinRehashedBucket, m_nMaxRehashedBucket;
+ EqualityFunc_t m_EqualityFunc;
+ HashFunc_t m_HashFunc;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: inserts an item into the map
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline int CUtlHashMapLarge<K,T,L,H>::InsertInternal( const KeyType_t &key, const ElemType_t &insert, EInsertPolicy ePolicy )
+{
+ // make sure we have room in the hash table
+ if ( m_cElements >= m_vecHashBuckets.Count() )
+ EnsureCapacity( MAX( 16, m_vecHashBuckets.Count() * 2 ) );
+ if ( m_cElements >= m_memNodes.Count() )
+ m_memNodes.Grow( m_memNodes.Count() * 2 );
+
+ // rehash incrementally
+ IncrementalRehash();
+
+ // hash the item
+ uint32 hash = m_HashFunc( key );
+
+ // migrate data forward, if necessary
+ int cBucketsToModAgainst = m_vecHashBuckets.Count() >> 1;
+ int iBucket = basetypes::ModPowerOf2(hash, cBucketsToModAgainst);
+ while ( iBucket >= m_nMinRehashedBucket
+ && !m_bitsMigratedBuckets.Get( iBucket ) )
+ {
+ RehashNodesInBucket( iBucket );
+ cBucketsToModAgainst >>= 1;
+ iBucket = basetypes::ModPowerOf2(hash, cBucketsToModAgainst);
+ }
+
+ // prevent duplicates if necessary
+ if ( ( ePolicy != eInsert_CreateDupes ) && m_cElements )
+ {
+ // look in the bucket to see if we have a conflict
+ int iBucket2 = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
+ IndexType_t iNode = FindInBucket( iBucket2, key );
+ if ( iNode != InvalidIndex() )
+ {
+ // a duplicate - update in place (matching CUtlMap)
+ if( ePolicy == eInsert_UpdateExisting )
+ {
+ m_memNodes[iNode].m_elem = insert;
+ }
+ return iNode;
+ }
+ }
+
+ // make an item
+ int iNewNode = AllocNode();
+ m_memNodes[iNewNode].m_iNextNode = InvalidIndex();
+ CopyConstruct( &m_memNodes[iNewNode].m_key, key );
+ CopyConstruct( &m_memNodes[iNewNode].m_elem, insert );
+
+ iBucket = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
+
+ // link ourselves in
+ // ::OutputDebugStr( CFmtStr( "insert %d into bucket %d\n", key, iBucket ).Access() );
+ LinkNodeIntoBucket( iBucket, iNewNode );
+
+ // return the new node
+ return iNewNode;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: grows the map to fit the specified amount
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline void CUtlHashMapLarge<K,T,L,H>::EnsureCapacity( int amount )
+{
+ m_memNodes.EnsureCapacity( amount );
+ // ::OutputDebugStr( CFmtStr( "grown m_memNodes from %d to %d\n", m_cElements, m_memNodes.Count() ).Access() );
+
+ if ( amount <= m_vecHashBuckets.Count() )
+ return;
+ int cBucketsNeeded = MAX( 16, m_vecHashBuckets.Count() );
+ while ( cBucketsNeeded < amount )
+ cBucketsNeeded *= 2;
+
+ // ::OutputDebugStr( CFmtStr( "grown m_vecHashBuckets from %d to %d\n", m_vecHashBuckets.Count(), cBucketsNeeded ).Access() );
+
+ // grow the hash buckets
+ int grow = cBucketsNeeded - m_vecHashBuckets.Count();
+ int iFirst = m_vecHashBuckets.AddMultipleToTail( grow );
+ // clear all the new data to invalid bits
+ memset( &m_vecHashBuckets[iFirst], 0xFFFFFFFF, grow*sizeof(m_vecHashBuckets[iFirst]) );
+ Assert( basetypes::IsPowerOf2( m_vecHashBuckets.Count() ) );
+
+ // we'll have to rehash, all the buckets that existed before growth
+ m_nMinRehashedBucket = 0;
+ m_nMaxRehashedBucket = iFirst;
+ if ( m_cElements > 0 )
+ {
+ // remove all the current bits
+ m_bitsMigratedBuckets.Resize( 0 );
+ // re-add new bits; these will all be reset to 0
+ m_bitsMigratedBuckets.Resize( m_vecHashBuckets.Count() );
+ }
+ else
+ {
+ // no elements - no rehashing
+ m_nMinRehashedBucket = m_vecHashBuckets.Count();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: gets a new node, from the free list if possible
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline int CUtlHashMapLarge<K,T,L,H>::AllocNode()
+{
+ // if we're out of free elements, get the max
+ if ( m_cElements == m_nMaxElement )
+ {
+ m_cElements++;
+ return m_nMaxElement++;
+ }
+
+ // pull from the free list
+ Assert( m_iNodeFreeListHead != InvalidIndex() );
+ int iNewNode = m_iNodeFreeListHead;
+ m_iNodeFreeListHead = FreeNodeIDToIndex( m_memNodes[iNewNode].m_iNextNode );
+ m_cElements++;
+ return iNewNode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: takes a bucket of nodes and re-hashes them into a more optimal bucket
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline void CUtlHashMapLarge<K,T,L,H>::RehashNodesInBucket( int iBucketSrc )
+{
+ // mark us as migrated
+ m_bitsMigratedBuckets.Set( iBucketSrc );
+
+ // walk the list of items, re-hashing them
+ IndexType_t iNode = m_vecHashBuckets[iBucketSrc].m_iNode;
+ while ( iNode != InvalidIndex() )
+ {
+ IndexType_t iNodeNext = m_memNodes[iNode].m_iNextNode;
+ Assert( iNodeNext != iNode );
+
+ // work out where the node should go
+ const KeyType_t &key = m_memNodes[iNode].m_key;
+ uint32 hash = m_HashFunc( key );
+ int iBucketDest = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
+
+ // if the hash bucket has changed, move it
+ if ( iBucketDest != iBucketSrc )
+ {
+ // ::OutputDebugStr( CFmtStr( "moved key %d from bucket %d to %d\n", key, iBucketSrc, iBucketDest ).Access() );
+
+ // remove from this bucket list
+ UnlinkNodeFromBucket( iBucketSrc, iNode );
+
+ // link into new bucket list
+ LinkNodeIntoBucket( iBucketDest, iNode );
+ }
+ iNode = iNodeNext;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: searches for an item by key, returning the index handle
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline int CUtlHashMapLarge<K,T,L,H>::Find( const KeyType_t &key ) const
+{
+ if ( m_cElements == 0 )
+ return InvalidIndex();
+
+ // hash the item
+ uint32 hash = m_HashFunc( key );
+
+ // find the bucket
+ int cBucketsToModAgainst = m_vecHashBuckets.Count();
+ int iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
+
+ // look in the bucket for the item
+ int iNode = FindInBucket( iBucket, key );
+ if ( iNode != InvalidIndex() )
+ return iNode;
+
+ // not found? we may have to look in older buckets
+ cBucketsToModAgainst >>= 1;
+ while ( cBucketsToModAgainst >= m_nMinRehashedBucket )
+ {
+ iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
+
+ if ( !m_bitsMigratedBuckets.Get( iBucket ) )
+ {
+ int iNode2 = FindInBucket( iBucket, key );
+ if ( iNode2 != InvalidIndex() )
+ return iNode2;
+ }
+
+ cBucketsToModAgainst >>= 1;
+ }
+
+ return InvalidIndex();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: searches for an item by key, returning the index handle
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline int CUtlHashMapLarge<K,T,L,H>::FindInBucket( int iBucket, const KeyType_t &key ) const
+{
+ if ( m_vecHashBuckets[iBucket].m_iNode != InvalidIndex() )
+ {
+ IndexType_t iNode = m_vecHashBuckets[iBucket].m_iNode;
+ Assert( iNode < m_nMaxElement );
+ while ( iNode != InvalidIndex() )
+ {
+ // equality check
+ if ( m_EqualityFunc( key, m_memNodes[iNode].m_key ) )
+ return iNode;
+
+ iNode = m_memNodes[iNode].m_iNextNode;
+ }
+ }
+
+ return InvalidIndex();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: links a node into a bucket
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+void CUtlHashMapLarge<K,T,L,H>::LinkNodeIntoBucket( int iBucket, int iNewNode )
+{
+ // add into the start of the bucket's list
+ m_memNodes[iNewNode].m_iNextNode = m_vecHashBuckets[iBucket].m_iNode;
+ m_vecHashBuckets[iBucket].m_iNode = iNewNode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: unlinks a node from the bucket
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+void CUtlHashMapLarge<K,T,L,H>::UnlinkNodeFromBucket( int iBucket, int iNodeToUnlink )
+{
+ int iNodeNext = m_memNodes[iNodeToUnlink].m_iNextNode;
+
+ // if it's the first node, just update the bucket to point to the new place
+ int iNode = m_vecHashBuckets[iBucket].m_iNode;
+ if ( iNode == iNodeToUnlink )
+ {
+ m_vecHashBuckets[iBucket].m_iNode = iNodeNext;
+ return;
+ }
+
+ // walk the list to find where
+ while ( iNode != InvalidIndex() )
+ {
+ if ( m_memNodes[iNode].m_iNextNode == iNodeToUnlink )
+ {
+ m_memNodes[iNode].m_iNextNode = iNodeNext;
+ return;
+ }
+ iNode = m_memNodes[iNode].m_iNextNode;
+ }
+
+ // should always be valid to unlink
+ Assert( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: removes a single item from the map
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline void CUtlHashMapLarge<K,T,L,H>::RemoveAt( IndexType_t i )
+{
+ if ( !IsValidIndex( i ) )
+ {
+ Assert( false );
+ return;
+ }
+
+ // unfortunately, we have to re-hash to find which bucket we're in
+ uint32 hash = m_HashFunc( m_memNodes[i].m_key );
+ int cBucketsToModAgainst = m_vecHashBuckets.Count();
+ int iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
+ if ( RemoveNodeFromBucket( iBucket, i ) )
+ return;
+
+ // wasn't found; look in older buckets
+ cBucketsToModAgainst >>= 1;
+ while ( cBucketsToModAgainst >= m_nMinRehashedBucket )
+ {
+ iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
+
+ if ( !m_bitsMigratedBuckets.Get( iBucket ) )
+ {
+ if ( RemoveNodeFromBucket( iBucket, i ) )
+ return;
+ }
+
+ cBucketsToModAgainst >>= 1;
+ }
+
+ // never found, container is busted
+ Assert( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: removes a node from the bucket, return true if it was found
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline bool CUtlHashMapLarge<K,T,L,H>::RemoveNodeFromBucket( IndexType_t iBucket, int iNodeToRemove )
+{
+ IndexType_t iNode = m_vecHashBuckets[iBucket].m_iNode;
+ while ( iNode != InvalidIndex() )
+ {
+ if ( iNodeToRemove == iNode )
+ {
+ // found it, remove
+ UnlinkNodeFromBucket( iBucket, iNodeToRemove );
+ Destruct( &m_memNodes[iNode].m_key );
+ Destruct( &m_memNodes[iNode].m_elem );
+
+ // link into free list
+ m_memNodes[iNode].m_iNextNode = FreeNodeIndexToID( m_iNodeFreeListHead );
+ m_iNodeFreeListHead = iNode;
+ m_cElements--;
+ if ( m_cElements == 0 )
+ {
+ m_nMinRehashedBucket = m_vecHashBuckets.Count();
+ }
+ return true;
+ }
+
+ iNode = m_memNodes[iNode].m_iNextNode;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: removes all items from the hash map
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline void CUtlHashMapLarge<K,T,L,H>::RemoveAll()
+{
+ FOR_EACH_MAP_FAST( *this, i )
+ {
+ Destruct( &m_memNodes[i].m_key );
+ Destruct( &m_memNodes[i].m_elem );
+ }
+
+ m_cElements = 0;
+ m_nMaxElement = 0;
+ m_iNodeFreeListHead = InvalidIndex();
+ m_nMinRehashedBucket = m_vecHashBuckets.Count();
+ m_nMaxRehashedBucket = InvalidIndex();
+ m_bitsMigratedBuckets.Resize( 0 );
+ memset( m_vecHashBuckets.Base(), 0xFF, m_vecHashBuckets.Count() * sizeof(HashBucket_t) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: removes all items from the hash map and releases memory
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline void CUtlHashMapLarge<K,T,L,H>::Purge()
+{
+ FOR_EACH_MAP_FAST( *this, i )
+ {
+ Destruct( &m_memNodes[i].m_key );
+ Destruct( &m_memNodes[i].m_elem );
+ }
+
+ m_cElements = 0;
+ m_nMaxElement = 0;
+ m_iNodeFreeListHead = InvalidIndex();
+ m_nMinRehashedBucket = InvalidIndex();
+ m_nMaxRehashedBucket = InvalidIndex();
+
+ m_bitsMigratedBuckets.Resize( 0 );
+ m_memNodes.Purge();
+ m_vecHashBuckets.Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: removes and deletes all items from the hash map and releases memory
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline void CUtlHashMapLarge<K,T,L,H>::PurgeAndDeleteElements()
+{
+ FOR_EACH_MAP_FAST( *this, i )
+ {
+ delete this->Element( i );
+ }
+
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: rehashes buckets
+//-----------------------------------------------------------------------------
+template <typename K, typename T, typename L, typename H>
+inline void CUtlHashMapLarge<K,T,L,H>::IncrementalRehash()
+{
+ if ( m_nMinRehashedBucket < m_nMaxRehashedBucket )
+ {
+ while ( m_nMinRehashedBucket < m_nMaxRehashedBucket )
+ {
+ // see if the bucket needs rehashing
+ if ( m_vecHashBuckets[m_nMinRehashedBucket].m_iNode != InvalidIndex()
+ && !m_bitsMigratedBuckets.Get(m_nMinRehashedBucket) )
+ {
+ // rehash this bucket
+ RehashNodesInBucket( m_nMinRehashedBucket );
+ // only actively do one - don't want to do it too fast since we may be on a rapid growth path
+ ++m_nMinRehashedBucket;
+ break;
+ }
+
+ // nothing to rehash in that bucket - increment and look again
+ ++m_nMinRehashedBucket;
+ }
+
+ if ( m_nMinRehashedBucket >= m_nMaxRehashedBucket )
+ {
+ // we're done; don't need any bits anymore
+ m_nMinRehashedBucket = m_vecHashBuckets.Count();
+ m_nMaxRehashedBucket = InvalidIndex();
+ m_bitsMigratedBuckets.Resize( 0 );
+ }
+ }
+}
+
+
+#endif // UTLHASHMAPLARGE_H