diff --git a/game/experiment/GameContent.txt b/game/experiment/GameContent.txt index 6657df4b63..516223a754 100644 --- a/game/experiment/GameContent.txt +++ b/game/experiment/GameContent.txt @@ -1,7 +1,8 @@ "GameContent" { - FileSystem + "filesystem" { - "AppId" 4000 + "garrysmod" "4000" + "cstrike" "240" } -} \ No newline at end of file +} diff --git a/game/experiment/addons/gmod_compatibility/scripts/lua/includes/modules/gmod_compatibility/sh_init.lua b/game/experiment/addons/gmod_compatibility/scripts/lua/includes/modules/gmod_compatibility/sh_init.lua index efd9e63826..2920e7c0b7 100644 --- a/game/experiment/addons/gmod_compatibility/scripts/lua/includes/modules/gmod_compatibility/sh_init.lua +++ b/game/experiment/addons/gmod_compatibility/scripts/lua/includes/modules/gmod_compatibility/sh_init.lua @@ -190,7 +190,24 @@ PrecacheParticleSystem = ParticleSystem.Precache engine.ActiveGamemode = function() return Gamemodes.GetActiveName() end -engine.GetGames = function() return {} end +engine.GetGames = function() + local games = Engine.GetMountableGames() + local result = {} + + for i, game in ipairs(games) do + result[i] = { + depot = game.appId, + title = game.name, + folder = game.directoryName, + + owned = game.isOwned, + mounted = game.isMounted, + installed = game.isInstalled, + } + end + + return result +end engine.GetAddons = function() return {} end -- TODO: Implement with our addon system engine.GetGamemodes = function() return {} end -- TODO: Implement with our gamemode system engine.GetUserContent = function() return {} end diff --git a/game/experiment/bin/game_shader_dx9.dll b/game/experiment/bin/game_shader_dx9.dll index 5068910431..ff028d6974 100644 --- a/game/experiment/bin/game_shader_dx9.dll +++ b/game/experiment/bin/game_shader_dx9.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cea7541ec85a23eb1cece63394c9954302cb5699f2fc33ae58e4d0314d4bf47 +oid sha256:8c73839b88256ee25a34c2196c3b5b050b117ffc878a33d105b54049d29893ff size 1041920 diff --git a/game/experiment/bin/game_shader_dx9.pdb b/game/experiment/bin/game_shader_dx9.pdb index c806feacd7..58c859b931 100644 --- a/game/experiment/bin/game_shader_dx9.pdb +++ b/game/experiment/bin/game_shader_dx9.pdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5cdfe0862dd4021fe06fe2b6da0e7fd7371d00132e759036df80f1838a600699 +oid sha256:55e48d42b404c6c1f4f557cd18af582f1fa43ed6e7da43339cd61bcf0f82e9f2 size 4091904 diff --git a/game/experiment/bin/luasocket.dll b/game/experiment/bin/luasocket.dll index 1da865462f..f3bd61eea8 100644 --- a/game/experiment/bin/luasocket.dll +++ b/game/experiment/bin/luasocket.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:63b59805dbfced6738aba04a170c3890acf47dd2ea6249ff3a0a83bd9aa30507 +oid sha256:2a9aae7ff1661a9bd28ed9a40564d78c53b64dbb0fa54a99bb86d1618781e4c8 size 581120 diff --git a/game/experiment/bin/luasocket.pdb b/game/experiment/bin/luasocket.pdb index f5aabb83d3..9c5bfaef64 100644 --- a/game/experiment/bin/luasocket.pdb +++ b/game/experiment/bin/luasocket.pdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9207706b6b93125665df19285eaf047aa2db9216fed655b5984f6a26169bf91 +oid sha256:36c2309d537cb7a6cbb13936a66ecd321e3bf855cb7011f34502a2ff9bb84591 size 2469888 diff --git a/game/experiment/menus/images/game-icons/dod.png b/game/experiment/menus/images/game-icons/dod.png new file mode 100644 index 0000000000..481513685b Binary files /dev/null and b/game/experiment/menus/images/game-icons/dod.png differ diff --git a/game/experiment/menus/images/game-icons/ep2.png b/game/experiment/menus/images/game-icons/ep2.png new file mode 100644 index 0000000000..730dc26fc8 Binary files /dev/null and b/game/experiment/menus/images/game-icons/ep2.png differ diff --git a/game/experiment/menus/images/game-icons/episodic.png b/game/experiment/menus/images/game-icons/episodic.png new file mode 100644 index 0000000000..730dc26fc8 Binary files /dev/null and b/game/experiment/menus/images/game-icons/episodic.png differ diff --git a/game/experiment/menus/images/game-icons/hl1mp.png b/game/experiment/menus/images/game-icons/hl1mp.png new file mode 100644 index 0000000000..126298d24c Binary files /dev/null and b/game/experiment/menus/images/game-icons/hl1mp.png differ diff --git a/game/experiment/menus/images/game-icons/lostcoast.png b/game/experiment/menus/images/game-icons/lostcoast.png new file mode 100644 index 0000000000..730dc26fc8 Binary files /dev/null and b/game/experiment/menus/images/game-icons/lostcoast.png differ diff --git a/game/experiment/menus/images/game-icons/portal.png b/game/experiment/menus/images/game-icons/portal.png new file mode 100644 index 0000000000..07d9910789 Binary files /dev/null and b/game/experiment/menus/images/game-icons/portal.png differ diff --git a/game/experiment/menus/images/game-icons/portal2.png b/game/experiment/menus/images/game-icons/portal2.png new file mode 100644 index 0000000000..ce32d19033 Binary files /dev/null and b/game/experiment/menus/images/game-icons/portal2.png differ diff --git a/game/experiment/menus/images/game-icons/tf.png b/game/experiment/menus/images/game-icons/tf.png new file mode 100644 index 0000000000..1c09bef7f8 Binary files /dev/null and b/game/experiment/menus/images/game-icons/tf.png differ diff --git a/game/experiment/menus/init.js b/game/experiment/menus/init.js index 96ac933e14..7f4fadbf2f 100644 --- a/game/experiment/menus/init.js +++ b/game/experiment/menus/init.js @@ -4,34 +4,68 @@ * on the window. */ document.addEventListener('DOMContentLoaded', function () { - if (!navigator.userAgent.includes('Valve Client')) { - window.g_Interop = window.g_Interop || {}; - window.g_Interop.__callbackQueue = window.g_Interop.__callbackQueue || []; - - window.g_Interop.__isReady = window.g_Interop.__isReady || false; - - if (!window.g_Interop.__isReady) { - window.g_Interop.DispatchReadyEvent = function () { - if (window.g_Interop.__isReady) return; - window.g_Interop.__isReady = true; - window.dispatchEvent(new Event('interop:ready')); - }; - - window.addEventListener('error', function (e) { - //alert('%s' + JSON.stringify(e)); - }); - - (function () { - let oldLog = console.log; - console.log = function () { - oldLog.apply(console, arguments); - //alert('%s' + JSON.stringify({ type: 'log', arguments: Array.prototype.slice.call(arguments) })); - }; - })(); - } - - window.dispatchEvent(new Event('interop:installmock')); - - window.g_Interop.DispatchReadyEvent(); + if (!navigator.userAgent.includes('Valve Client')) { + window.g_Interop = window.g_Interop || {}; + window.g_Interop.__callbackQueue = window.g_Interop.__callbackQueue || []; + + window.g_Interop.__isReady = window.g_Interop.__isReady || false; + + if (!window.g_Interop.__isReady) { + window.g_Interop.DispatchReadyEvent = function () { + if (window.g_Interop.__isReady) return; + window.g_Interop.__isReady = true; + window.dispatchEvent(new Event('interop:ready')); + }; + + window.addEventListener('error', function (e) { + //alert('%s' + JSON.stringify(e)); + }); + + (function () { + let oldLog = console.log; + console.log = function () { + oldLog.apply(console, arguments); + //alert('%s' + JSON.stringify({ type: 'log', arguments: Array.prototype.slice.call(arguments) })); + }; + })(); } + + window.dispatchEvent(new Event('interop:installmock')); + + window.g_Interop.DispatchReadyEvent(); + } }); + +let loadingOverlay; + +document.addEventListener('DOMContentLoaded', function () { + loadingOverlay = document.createElement('div'); + loadingOverlay.classList.add('hidden', 'inset-0', 'fixed', 'bg-black', 'bg-opacity-50', 'flex', 'items-center', 'justify-center'); + loadingOverlay.innerHTML = ` +
+
Loading...
+ + + + +
+ `; + document.body.appendChild(loadingOverlay); +}); + +function showLoadingOverlay(text, callback) { + const loadingText = loadingOverlay.querySelector('#loadingText'); + loadingText.textContent = text || 'Loading...'; + + loadingOverlay.classList.remove('hidden'); + + const finish = () => { + hideLoadingOverlay(); + } + + callback(finish); +} + +function hideLoadingOverlay() { + loadingOverlay.classList.add('hidden'); +} diff --git a/game/experiment/menus/main.js b/game/experiment/menus/main.js index 12f8a7044d..93240c62e1 100644 --- a/game/experiment/menus/main.js +++ b/game/experiment/menus/main.js @@ -5,11 +5,11 @@ const BACKGROUND_LEVEL = 3; const BACKGROUND_DISCONNECTED = 4; function SetBackgroundRenderState(state) { - if (state === BACKGROUND_LEVEL) { - document.body.classList.add('in-level'); - } else { - document.body.classList.remove('in-level'); - } + if (state === BACKGROUND_LEVEL) { + document.body.classList.add('in-level'); + } else { + document.body.classList.remove('in-level'); + } } const pageElement = document.querySelector('#page'); @@ -23,228 +23,263 @@ const registeredPages = new Map(); let currentPage = null; pageCloseElement.addEventListener('click', () => { - if (currentPage) { - currentPage.hide(); - currentPage = null; - } + if (currentPage) { + currentPage.hide(); + currentPage = null; + } }); // Custom element for links customElements.define('game-menu-link', class extends HTMLElement { - constructor() { - super(); + constructor() { + super(); - this.addEventListener('click', this.onClick); + this.addEventListener('click', this.onClick); - this.classList.add('group', 'flex', 'gap-2', 'items-center', 'hover:scale-125', 'cursor-pointer', 'transition'); + this.classList.add('group', 'flex', 'gap-2', 'items-center', 'hover:scale-125', 'cursor-pointer', 'transition'); - if (this.hasAttribute('label-above')) { - this.classList.add('flex-col-reverse'); - } else { - this.classList.add('flex-col'); - } - - const key = this.getAttribute('translation'); - console.log(key); // TODO: request the menu for translations - // this.textContent = menus.localize.getTranslation(key); // TODO: Set this on the span (not the element itself) or sub-links will break + if (this.hasAttribute('label-above')) { + this.classList.add('flex-col-reverse'); + } else { + this.classList.add('flex-col'); } - connectedCallback() { - const sizeClassImage = this.hasAttribute('small') ? 'w-12 h-12' : 'w-24 h-24'; - const sizeClassText = this.hasAttribute('small') ? 'text-sm' : 'text-md'; - this.innerHTML = ` + const key = this.getAttribute('translation'); + console.log(key); // TODO: request the menu for translations + // this.textContent = menus.localize.getTranslation(key); // TODO: Set this on the span (not the element itself) or sub-links will break + } + + connectedCallback() { + const sizeClassImage = this.hasAttribute('small') ? 'w-12 h-12' : 'w-24 h-24'; + const sizeClassText = this.hasAttribute('small') ? 'text-sm' : 'text-md'; + this.innerHTML = ` ${this.textContent} ${this.textContent} `; - } + } - onClick(event) { - event.preventDefault(); + onClick(event) { + event.preventDefault(); - const href = this.getAttribute('href'); + const href = this.getAttribute('href'); - if (href) { - if (currentPage) { - currentPage.hide(); - } + if (href) { + if (currentPage) { + currentPage.hide(); + } - window.location.href = href; - return; - } + window.location.href = href; + return; + } - const pageRef = this.getAttribute('pageref'); + const pageRef = this.getAttribute('pageref'); - if (pageRef) { - const registeredPage = registeredPages.get(pageRef); + if (pageRef) { + const registeredPage = registeredPages.get(pageRef); - if (registeredPage.isShowing()) { - registeredPage.hide(); - return; - } + if (registeredPage.isShowing()) { + registeredPage.hide(); + return; + } - if (currentPage) { - currentPage.hide(); - } + if (currentPage) { + currentPage.hide(); + } - registeredPage.show(); - currentPage = registeredPage; - return; - } + registeredPage.show(); + currentPage = registeredPage; + return; } + } }); // Custom element for pages (invisible until selected) customElements.define('game-page', class extends HTMLElement { - _lastShowHandler = 0; - _isShowing = false; + _lastShowHandler = 0; + _isShowing = false; - constructor() { - super(); + constructor() { + super(); - this.classList.add('hidden'); - } - - connectedCallback() { - registeredPages.set(this.id, this); - } + this.classList.add('hidden'); + } - show() { - this._isShowing = true; - this._lastShowHandler++; + connectedCallback() { + registeredPages.set(this.id, this); + } - pageTitleElement.textContent = this.getAttribute('title'); - // pageContentElement.innerHTML = this.innerHTML; // This messes up any values set (e.g: checked on checkboxes) - // Lets teleport the children instead - while (this.firstChild) { - pageContentElement.appendChild(this.firstChild); - } + show() { + this._isShowing = true; + this._lastShowHandler++; - pageElement.classList.remove('opacity-0'); + pageTitleElement.textContent = this.getAttribute('title'); + // pageContentElement.innerHTML = this.innerHTML; // This messes up any values set (e.g: checked on checkboxes) + // Lets teleport the children instead + while (this.firstChild) { + pageContentElement.appendChild(this.firstChild); } - isShowing() { - return this._isShowing; - } + pageElement.classList.remove('opacity-0'); + } - hide() { - this._isShowing = false; + isShowing() { + return this._isShowing; + } - const showHandler = this._lastShowHandler; + hide() { + this._isShowing = false; - pageElement.classList.add('opacity-0'); + const showHandler = this._lastShowHandler; - // Move the children back after the animation - setTimeout(() => { - // Don't move them if the show handler changed, meaning the page was shown again - // (happens when spam clicking) - if (showHandler !== this._lastShowHandler) { - return; - } + pageElement.classList.add('opacity-0'); - while (pageContentElement.firstChild) { - this.appendChild(pageContentElement.firstChild); - } - }, 500); - } + // Move the children back after the animation + setTimeout(() => { + // Don't move them if the show handler changed, meaning the page was shown again + // (happens when spam clicking) + if (showHandler !== this._lastShowHandler) { + return; + } + + while (pageContentElement.firstChild) { + this.appendChild(pageContentElement.firstChild); + } + }, 500); + } }); // Source: https://codepen.io/marcusparsons/pen/NMyzgR function makeDraggable(element) { - let currentPosX = 0, currentPosY = 0, previousPosX = 0, previousPosY = 0; - element.querySelector('[x-draggable-handle]').onmousedown = dragMouseDown; - - function dragMouseDown(e) { - e.preventDefault(); - // Get the mouse cursor position and set the initial previous positions to begin - previousPosX = e.clientX; - previousPosY = e.clientY; - // When the mouse is let go, call the closing event - document.onmouseup = closeDragElement; - // call a function whenever the cursor moves - document.onmousemove = elementDrag; - } - - function elementDrag(e) { - e.preventDefault(); - // Calculate the new cursor position by using the previous x and y positions of the mouse - currentPosX = previousPosX - e.clientX; - currentPosY = previousPosY - e.clientY; - // Replace the previous positions with the new x and y positions of the mouse - previousPosX = e.clientX; - previousPosY = e.clientY; - // Set the element's new position - element.style.top = (element.offsetTop - currentPosY) + 'px'; - element.style.left = (element.offsetLeft - currentPosX) + 'px'; - } - - function closeDragElement() { - document.onmouseup = null; - document.onmousemove = null; - } + let currentPosX = 0, currentPosY = 0, previousPosX = 0, previousPosY = 0; + element.querySelector('[x-draggable-handle]').onmousedown = dragMouseDown; + + function dragMouseDown(e) { + e.preventDefault(); + // Get the mouse cursor position and set the initial previous positions to begin + previousPosX = e.clientX; + previousPosY = e.clientY; + // When the mouse is let go, call the closing event + document.onmouseup = closeDragElement; + // call a function whenever the cursor moves + document.onmousemove = elementDrag; + } + + function elementDrag(e) { + e.preventDefault(); + // Calculate the new cursor position by using the previous x and y positions of the mouse + currentPosX = previousPosX - e.clientX; + currentPosY = previousPosY - e.clientY; + // Replace the previous positions with the new x and y positions of the mouse + previousPosX = e.clientX; + previousPosY = e.clientY; + // Set the element's new position + element.style.top = (element.offsetTop - currentPosY) + 'px'; + element.style.left = (element.offsetLeft - currentPosX) + 'px'; + } + + function closeDragElement() { + document.onmouseup = null; + document.onmousemove = null; + } } document.querySelectorAll('[x-draggable]').forEach(makeDraggable); +/** + * Loads the mountable content info from the game, populating the list + * and setting up the event listeners for mounting and unmounting content. + */ function initialize() { - GameUI.LoadMountableContentInfo(function (registeredMountableContent) { - registeredMountableContent.forEach((content, index) => { - const contentItemElement = contentItemTemplateElement.content.firstElementChild.cloneNode(true); - - contentItemElement.classList.add(index % 2 === 0 ? 'bg-white/10' : 'bg-white/5'); + GameUI.LoadMountableContentInfo(function (registeredMountableContent) { + // sort it by name first + registeredMountableContent.sort((a, b) => a.name.localeCompare(b.name)); + registeredMountableContent.forEach((content, index) => { + const contentItemElement = contentItemTemplateElement.content.firstElementChild.cloneNode(true); + + contentItemElement.classList.add(index % 2 === 0 ? 'bg-white/10' : 'bg-white/5'); + + const iconElement = contentItemElement.querySelector('img'); + iconElement.src = content.icon; + iconElement.alt = content.name; + + const nameElement = contentItemElement.querySelector('span'); + nameElement.textContent = content.name; + + const inputElement = contentItemElement.querySelector('input'); + inputElement.value = content.id; + inputElement.checked = content.mounted; + + inputElement.addEventListener('change', () => { + showLoadingOverlay('Mounting content...', function (finish) { + if (inputElement.checked) { + GameUI.MountGameContent(inputElement.value, function (wasSuccessful) { + if (!wasSuccessful) { + inputElement.checked = false; + } + + finish(); + }); + } else { + GameUI.UnmountGameContent(inputElement.value, function (wasSuccessful) { + if (!wasSuccessful) { + inputElement.checked = true; + } - const iconElement = contentItemElement.querySelector('img'); - iconElement.src = content.icon; - iconElement.alt = content.name; + finish(); + }); + } + }); + }); - const nameElement = contentItemElement.querySelector('span'); - nameElement.textContent = content.name; + contentItemElement.addEventListener('click', (ev) => { + // Don't toggle the checkbox if the click was on the checkbox itself + // otherwise we immediately toggle it back + if (ev.target.tagName === 'INPUT') { + return; + } - const inputElement = contentItemElement.querySelector('input'); - inputElement.value = content.id; - inputElement.checked = content.mounted; + inputElement.checked = !inputElement.checked; + inputElement.dispatchEvent(new Event('change')); + }); - contentItemElement.addEventListener('click', () => { - inputElement.checked = !inputElement.checked; - }); - - contentList.appendChild(contentItemElement); - }); + contentList.appendChild(contentItemElement); }); + }); } window.addEventListener('interop:ready', () => { - // Intro effect when the page is loaded - document.body.classList.add('loaded'); + // Intro effect when the page is loaded + document.body.classList.add('loaded'); - initialize(); + initialize(); }); // When working in the browser we want to mock the GameUI API window.addEventListener('interop:installmock', () => { - window.GameUI = { - LoadMountableContentInfo: function (callback) { - callback([ - { - id: 'gmod', - name: 'Garry\'s Mod', - mounted: true, - icon: './images/game-icons/garrysmod.png', - }, - { - id: 'cstrike', - name: 'Counter-Strike: Source', - mounted: false, - icon: './images/game-icons/cstrike.png', - }, - { - id: 'hl2', - name: 'Dev Note: this mountable game data is mocked', - mounted: false, - icon: './images/game-icons/hl2.png', - }, - ]); + window.GameUI = { + LoadMountableContentInfo: function (callback) { + callback([ + { + id: 4000, + name: 'Garry\'s Mod', + mounted: true, + icon: './images/game-icons/garrysmod.png', + }, + { + id: 240, + name: 'Counter-Strike: Source', + mounted: false, + icon: './images/game-icons/cstrike.png', + }, + { + id: 220, + name: 'Dev Note: this mountable game data is mocked', + mounted: false, + icon: './images/game-icons/hl2.png', }, - }; + ]); + }, + }; }); diff --git a/src/game/client/cdll_client_int.cpp b/src/game/client/cdll_client_int.cpp index d862d1c638..fd9bf3a8dd 100644 --- a/src/game/client/cdll_client_int.cpp +++ b/src/game/client/cdll_client_int.cpp @@ -1065,7 +1065,7 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, #if defined( EXPERIMENT_SOURCE ) // Andrew; then mount everything the user wants to use. - MountUserContent(); + InitializeGameContentMounting(); // Finally, load all of the player's addons. MountAddons(); diff --git a/src/game/client/client_base.vpc b/src/game/client/client_base.vpc index a7a4285aae..2ba8316d1d 100644 --- a/src/game/client/client_base.vpc +++ b/src/game/client/client_base.vpc @@ -544,6 +544,7 @@ $Project $File "lc_baseentity.cpp" $File "lc_baseplayer.cpp" $File "$SRCDIR\public\lcdll_int.cpp" + $File "$SRCDIR\public\lengine_shared.cpp" $File "lcdll_util.cpp" $File "$SRCDIR\public\lColor.cpp" $File "$SRCDIR\public\tier1\lconvar.cpp" diff --git a/src/game/client/experiment/ui/mainmenu.cpp b/src/game/client/experiment/ui/mainmenu.cpp index 2c1b32c991..7157d95562 100644 --- a/src/game/client/experiment/ui/mainmenu.cpp +++ b/src/game/client/experiment/ui/mainmenu.cpp @@ -12,6 +12,7 @@ #include #include "GameUI/IGameConsole.h" #include "vgui/IInput.h" +#include using namespace vgui; @@ -170,6 +171,8 @@ class MainMenuHTML : public HTML { AddJavascriptObject( "GameUI" ); AddJavascriptObjectCallback( "GameUI", "LoadMountableContentInfo" ); + AddJavascriptObjectCallback( "GameUI", "MountGameContent" ); + AddJavascriptObjectCallback( "GameUI", "UnmountGameContent" ); } virtual void OnJavaScriptCallback( KeyValues *pData ) OVERRIDE @@ -184,29 +187,52 @@ class MainMenuHTML : public HTML // DevMsg( "Argument: %s (inside %s.%s call)\n", pArg->GetName(), pszObject, pszProperty ); // } - if ( Q_strcmp( pszObject, "GameUI" ) == 0 ) + // This panel only handles GameUI callbacks + if ( Q_strcmp( pszObject, "GameUI" ) != 0 ) + return; + + if ( Q_strcmp( pszProperty, "LoadMountableContentInfo" ) == 0 ) { - if ( Q_strcmp( pszProperty, "LoadMountableContentInfo" ) == 0 ) + KeyValues *pParameters = new KeyValues( "parameters" ); + CUtlVector< mountableGame_t > &mountableGames = GetMountableGames(); + + KeyValues *pMountableGames = new KeyValues( "mountableGames" ); + pParameters->AddSubKey( pMountableGames ); + + for ( int i = 0; i < mountableGames.Count(); i++ ) { - // TODO: Load this automatically: - KeyValues *pResponse = new KeyValues( "response" ); - - KeyValues *pGarrysMod = new KeyValues( "" ); - pGarrysMod->SetString( "icon", "images/game-icons/garrysmod.png" ); - pGarrysMod->SetString( "name", "Garry's Mod" ); - pGarrysMod->SetString( "id", "garrysmod" ); - pGarrysMod->SetBool( "mounted", true ); - pResponse->AddSubKey( pGarrysMod ); - - KeyValues *pCounterStrike = new KeyValues( "" ); - pCounterStrike->SetString( "icon", "images/game-icons/cstrike.png" ); - pCounterStrike->SetString( "name", "Counter-Strike: Source" ); - pCounterStrike->SetString( "id", "cstrike" ); - pCounterStrike->SetBool( "mounted", false ); - pResponse->AddSubKey( pCounterStrike ); - - CallJavascriptObjectCallback( callbackId, pResponse ); + mountableGame_t &game = mountableGames[i]; + + char icon[MAX_PATH]; + Q_snprintf( icon, sizeof( icon ), "images/game-icons/%s.png", game.directoryName ); + + KeyValues *pGame = new KeyValues( "" ); + pGame->SetString( "icon", icon ); + pGame->SetString( "name", game.name ); + pGame->SetInt( "id", game.appId ); + pGame->SetBool( "mounted", game.isMounted ); + pMountableGames->AddSubKey( pGame ); } + + CallJavascriptObjectCallback( callbackId, pParameters ); + } + else if ( Q_strcmp( pszProperty, "MountGameContent" ) == 0 ) + { + KeyValues *pArguments = pData->FindKey( "arguments" ); + int nGameAppId = pArguments->GetInt( "1" ); + + KeyValues *pResponse = new KeyValues( "parameters" ); + pResponse->SetBool( "wasSuccessful", MountGameContentByAppId( nGameAppId ) ); + CallJavascriptObjectCallback( callbackId, pResponse ); + } + else if ( Q_strcmp( pszProperty, "UnmountGameContent" ) == 0 ) + { + KeyValues *pArguments = pData->FindKey( "arguments" ); + int nGameAppId = pArguments->GetInt( "1" ); + + KeyValues *pResponse = new KeyValues( "parameters" ); + pResponse->SetBool( "wasSuccessful", UnmountGameContentByAppId( nGameAppId ) ); + CallJavascriptObjectCallback( callbackId, pResponse ); } } }; diff --git a/src/game/client/scripted_controls/lHTML.cpp b/src/game/client/scripted_controls/lHTML.cpp index 6d81dcc77e..51cef89d11 100644 --- a/src/game/client/scripted_controls/lHTML.cpp +++ b/src/game/client/scripted_controls/lHTML.cpp @@ -44,7 +44,9 @@ void LHTML::OnJavaScriptCallback( KeyValues *pData ) // Push all arguments in 'arguments' as a table lua_newtable( L ); - for ( KeyValues *pArg = pData->FindKey( "arguments" ); pArg; pArg = pArg->GetNextKey() ) + KeyValues *pArguments = pData->FindKey( "arguments" ); + + for ( KeyValues *pArg = pArguments->GetFirstSubKey(); pArg; pArg = pArg->GetNextKey() ) { lua_pushstring( L, pArg->GetName() ); lua_pushstring( L, pArg->GetString() ); diff --git a/src/game/server/gameinterface.cpp b/src/game/server/gameinterface.cpp index 4deafe0882..f20f80d661 100644 --- a/src/game/server/gameinterface.cpp +++ b/src/game/server/gameinterface.cpp @@ -698,7 +698,7 @@ bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory, #if defined( EXPERIMENT_SOURCE ) // Andrew; then mount everything the user wants to use. - MountUserContent(); + InitializeGameContentMounting(); // Finally, load all of the player's addons. MountAddons(); diff --git a/src/game/server/server_base.vpc b/src/game/server/server_base.vpc index 935685ddae..9ff0e3f40a 100644 --- a/src/game/server/server_base.vpc +++ b/src/game/server/server_base.vpc @@ -714,7 +714,8 @@ $Project $File "$SRCDIR\public\tier0\ldbg.cpp" $File "$SRCDIR\game\shared\leffect_dispatch_data.cpp" $File "$SRCDIR\game\shared\lentitylist.cpp" - $File "$SRCDIR\public\leiface.cpp" + $File "$SRCDIR\public\lengine.cpp" + $File "$SRCDIR\public\lengine_shared.cpp" $File "$SRCDIR\public\lfilesystem.cpp" $File "$SRCDIR\public\lgametrace.cpp" $File "$SRCDIR\public\lglobalvars_base.cpp" diff --git a/src/game/shared/experiment/util/jsontokv.cpp b/src/game/shared/experiment/util/jsontokv.cpp index 2c2ef8fc72..72124fbe6c 100644 --- a/src/game/shared/experiment/util/jsontokv.cpp +++ b/src/game/shared/experiment/util/jsontokv.cpp @@ -41,9 +41,31 @@ inline void MapNode( Value::ConstMemberIterator itr, KeyValues *kv ) pKv->SetName( itr->name.GetString() ); for ( Value::ConstValueIterator arrItr = itr->value.Begin(); arrItr != itr->value.End(); ++arrItr ) { - // We can only support arrays of objects... for now if ( arrItr->GetType() == kObjectType ) IterObject( nullptr, arrItr->GetObject(), pKv ); + else + { + char keyName[12]; + pKv->GetNextKeyName( keyName, sizeof( keyName ) ); + + if ( arrItr->GetType() == kNumberType ) + { + if ( arrItr->IsInt() ) + pKv->SetInt( keyName, arrItr->GetInt() ); + else if ( arrItr->IsUint64() ) + pKv->SetUint64( keyName, arrItr->GetUint64() ); + else if ( arrItr->IsLosslessFloat() ) + pKv->SetFloat( keyName, arrItr->GetFloat() ); + else // Default to float + pKv->SetFloat( keyName, arrItr->GetDouble() ); + } + else if ( arrItr->GetType() == kStringType ) + pKv->SetString( keyName, arrItr->GetString() ); + else if ( arrItr->GetType() == kTrueType || arrItr->GetType() == kFalseType ) + pKv->SetBool( keyName, arrItr->GetType() == kTrueType ); + else + DevWarning( "Unsupported data type in JSON array %i!\n", arrItr->GetType() ); + } // MOM_TODO: theoretically any array can work, it's just the keys would be disregarded, like the array of objects are // Consider creating garbage keys for used values, and iterating over only values of the array. // The thing to keep in mind is that whoever is reading the array would know what data type it should be... @@ -111,7 +133,7 @@ inline void WriteObject(KeyValues* kv, PrettyWriter< StringBuffer >& writer) inline void WriteObjectOrArray( KeyValues *kv, PrettyWriter< StringBuffer > &writer ) { - const char *pName = kv->GetFirstSubKey()->GetName(); + const char *pName = kv->GetFirstSubKey() ? kv->GetFirstSubKey()->GetName() : nullptr; const bool bIsObject = pName && *pName; if ( bIsObject ) diff --git a/src/game/shared/lsrcinit.cpp b/src/game/shared/lsrcinit.cpp index 236212a206..305ee616ec 100644 --- a/src/game/shared/lsrcinit.cpp +++ b/src/game/shared/lsrcinit.cpp @@ -51,6 +51,7 @@ static const luaL_RegForState luasrclibs[] = { { LUA_EFFECTDATALIBNAME, luaopen_CEffectData, REALM_SHARED }, { LUA_EFLIBNAME, luaopen_EF, REALM_SHARED | REALM_GAMEUI }, { LUA_ENGINEFLAGSLIBNAME, luaopen_FL, REALM_SHARED | REALM_GAMEUI }, + { LUA_ENGINELIBNAME, luaopen_engine_shared, REALM_SHARED | REALM_GAMEUI }, { LUA_ENGINELIBNAME, luaopen_engine, REALM_SHARED | REALM_GAMEUI }, { LUA_ENTLISTLIBNAME, luaopen_EntityList, REALM_SHARED }, { LUA_EXPERIMENTPLAYERLIBNAME, luaopen_CExperiment_Player_shared, REALM_SHARED }, diff --git a/src/game/shared/luasrclib.h b/src/game/shared/luasrclib.h index 3a42e7497f..87e99291bf 100644 --- a/src/game/shared/luasrclib.h +++ b/src/game/shared/luasrclib.h @@ -75,6 +75,7 @@ LUALIB_API int( luaopen_debugoverlay )( lua_State *L ); LUALIB_API int( luaopen_EF )( lua_State *L ); #define LUA_ENGINELIBNAME "Engine" +LUALIB_API int( luaopen_engine_shared )( lua_State *L ); LUALIB_API int( luaopen_engine )( lua_State *L ); #define LUA_ENTLISTLIBNAME "EntityList" diff --git a/src/game/shared/mountaddons.cpp b/src/game/shared/mountaddons.cpp index 62d04063d5..a72e73001d 100644 --- a/src/game/shared/mountaddons.cpp +++ b/src/game/shared/mountaddons.cpp @@ -39,7 +39,7 @@ void MountAddon( const char *addonName ) if ( bGetCurrentDirectory ) V_SetCurrentDirectory( currentDirectoryPath ); -#ifdef GAME_DLL +#ifdef GAME_DLL // Prevent the message from printing twice in clients ConColorMsg( Color( 200, 255, 0, 255 ), "Mounting addon \"%s\"...\n", addonName ); #endif diff --git a/src/game/shared/mountsteamcontent.cpp b/src/game/shared/mountsteamcontent.cpp index 0b40419dc6..915efe6b04 100644 --- a/src/game/shared/mountsteamcontent.cpp +++ b/src/game/shared/mountsteamcontent.cpp @@ -13,38 +13,14 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -struct mountableGame_t -{ - const char *name; - int appId; - CUtlVector< const char * > vpks; - - mountableGame_t( const char *gameName, int gameId ) - : name( gameName ), appId( gameId ) {} - - mountableGame_t( const mountableGame_t &other ) - : name( other.name ), appId( other.appId ) - { - for ( int i = 0; i < other.vpks.Count(); i++ ) - { - vpks.AddToTail( other.vpks[i] ); - } - } - - void AddVPK( const char *vpkPath ) - { - vpks.AddToTail( vpkPath ); - } -}; - static CUtlVector< mountableGame_t > g_GamePaths; -#define REGISTER_GAME( game_name, game_id ) \ - g_GamePaths.AddToTail( mountableGame_t( game_name, game_id ) ); +#define REGISTER_GAME( pSteamApps, GameName, GameDirectory, GameAppId ) \ + g_GamePaths.AddToTail( mountableGame_t( GameName, GameDirectory, GameAppId, pSteamApps->BIsAppInstalled( GameAppId ), pSteamApps->BIsSubscribedApp( GameAppId ) ) ); -#define REGISTER_GAME_WITH_VPK( game_name, game_id, ... ) \ +#define REGISTER_GAME_WITH_VPK( pSteamApps, GameName, GameDirectory, GameAppId, ... ) \ { \ - mountableGame_t game( game_name, game_id ); \ + mountableGame_t game( GameName, GameDirectory, GameAppId, pSteamApps->BIsAppInstalled( GameAppId ), pSteamApps->BIsSubscribedApp( GameAppId ) ); \ const char *vpkPaths[] = { __VA_ARGS__ }; \ for ( int i = 0; i < ARRAYSIZE( vpkPaths ); i++ ) \ { \ @@ -73,17 +49,17 @@ void AddSearchPathByAppId( int nAppId ) char fullPath[MAX_PATH]; // Commented because it's wrong anyway. g_GamePaths[2] always pointed to cstrike :/ - //if ( g_GamePaths[i].appId == HL1MP_APPID ) + // if ( g_GamePaths[i].appId == HL1MP_APPID ) //{ // // Andrew; Half-Life Deathmatch: Source requires Half-Life: Source's path added!! - // Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, g_GamePaths[2].name ); + // Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, g_GamePaths[2].directoryName ); // filesystem->AddSearchPath( fullPath, "GAME", PATH_ADD_TO_TAIL ); //} if ( g_GamePaths[i].appId != nAppId ) continue; - Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, g_GamePaths[i].name ); + Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, g_GamePaths[i].directoryName ); filesystem->AddSearchPath( fullPath, "GAME", PATH_ADD_TO_TAIL ); auto &vpkPaths = g_GamePaths[i].vpks; @@ -93,23 +69,89 @@ void AddSearchPathByAppId( int nAppId ) Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, vpkPaths[j] ); filesystem->AddSearchPath( fullPath, "GAME", PATH_ADD_TO_TAIL ); } + + g_GamePaths[i].isMounted = true; + +#ifdef CLIENT_DLL // Prevent the message from printing twice in clients + ConColorMsg( Color( 200, 255, 0, 255 ), "Mounting game content \"%s\"...\n", g_GamePaths[i].name ); +#endif + + // We've found the game, no need to continue searching. + break; } } -void MountUserContent() +void RemoveSearchPathByAppId( int nAppId ) { - REGISTER_GAME( "hl2", 220 ); - REGISTER_GAME( "cstrike", 240 ); - REGISTER_GAME( "hl1", 280 ); - REGISTER_GAME( "dod", 300 ); - REGISTER_GAME( "lostcoast", 340 ); - REGISTER_GAME( "hl1mp", HL1MP_APPID ); - REGISTER_GAME( "episodic", 380 ); - REGISTER_GAME( "portal", 400 ); - REGISTER_GAME( "ep2", 420 ); - REGISTER_GAME( "tf", 440 ); - - REGISTER_GAME_WITH_VPK( "garrysmod", 4000, "garrysmod/fallback_dir.vpk", "garrysmod/garrysmod_dir.vpk" ); + ISteamApps *pSteamApps = steamapicontext->SteamApps(); + + if ( !pSteamApps->BIsAppInstalled( nAppId ) ) + { + Warning( "Failed to unmount content for App ID %i (not installed)\n", nAppId ); + return; + } + + char appInstallPath[MAX_PATH * 2]; + pSteamApps->GetAppInstallDir( nAppId, appInstallPath, sizeof( appInstallPath ) ); + + for ( int i = 0; i < g_GamePaths.Count(); i++ ) + { + char fullPath[MAX_PATH]; + + if ( g_GamePaths[i].appId != nAppId ) + continue; + + Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, g_GamePaths[i].directoryName ); + filesystem->RemoveSearchPath( fullPath ); + + auto &vpkPaths = g_GamePaths[i].vpks; + + for ( int j = 0; j < vpkPaths.Count(); j++ ) + { + Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, vpkPaths[j] ); + filesystem->RemoveSearchPath( fullPath ); + } + + g_GamePaths[i].isMounted = false; + +#ifdef CLIENT_DLL // Prevent the message from printing twice in clients + ConColorMsg( Color( 200, 255, 0, 255 ), "Unmounting game content \"%s\"...\n", g_GamePaths[i].name ); +#endif + + // We've found the game, no need to continue searching. + break; + } + + // Andrew; Half-Life Deathmatch: Source requires Half-Life: Source's path added!! + // if ( nAppId == HL1MP_APPID ) + //{ + // Q_snprintf( fullPath, sizeof( fullPath ), "%s/%s", appInstallPath, g_GamePaths[2].directoryName ); + // filesystem->RemoveSearchPath( fullPath ); + //} +} + +CUtlVector< mountableGame_t > &GetMountableGames() +{ + return g_GamePaths; +} + +void InitializeGameContentMounting() +{ + ISteamApps *pSteamApps = steamapicontext->SteamApps(); + + REGISTER_GAME( pSteamApps, "Half-Life 2", "hl2", 220 ); + REGISTER_GAME( pSteamApps, "Half-Life", "hl1", 280 ); + + REGISTER_GAME( pSteamApps, "Day of Defeat: Source", "dod", 300 ); + REGISTER_GAME( pSteamApps, "Half-Life 2: Lost Coast", "lostcoast", 340 ); + REGISTER_GAME( pSteamApps, "Half-Life Deathmatch: Source", "hl1mp", HL1MP_APPID ); + REGISTER_GAME( pSteamApps, "Half-Life 2: Episode One", "episodic", 380 ); + REGISTER_GAME( pSteamApps, "Portal", "portal", 400 ); + REGISTER_GAME( pSteamApps, "Half-Life 2: Episode Two", "ep2", 420 ); + REGISTER_GAME( pSteamApps, "Team Fortress 2", "tf", 440 ); + + REGISTER_GAME_WITH_VPK( pSteamApps, "Counter-Strike: Source", "cstrike", 240, "cstrike/cstrike_pak_dir.vpk" ); + REGISTER_GAME_WITH_VPK( pSteamApps, "Garry's Mod", "garrysmod", 4000, "garrysmod/fallback_dir.vpk", "garrysmod/garrysmod_dir.vpk" ); KeyValues *pMainFile, *pFileSystemInfo; #ifdef CLIENT_DLL @@ -145,17 +187,162 @@ void MountUserContent() for ( KeyValues *pKey = pFileSystemInfo->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey() ) { - if ( strcmp( pKey->GetName(), "AppId" ) != 0 ) - continue; + // pKey->GetName() is garrysmod/cstrike/etc + int nAppId = pKey->GetInt(); - int nExtraContentId = pKey->GetInt(); - - if ( nExtraContentId ) + if ( nAppId ) { - AddSearchPathByAppId( nExtraContentId ); + AddSearchPathByAppId( nAppId ); } } } pMainFile->deleteThis(); } + +/// +/// Adds the specified game to the gamecontent.txt file and mounts the content for the specified game. +/// +/// The AppID of the game to mount the content for. +/// Whether the game was successfully mounted. +bool MountGameContentByAppId( int nAppId ) +{ + mountableGame_t *pGameToMount = nullptr; + + for ( int i = 0; i < g_GamePaths.Count(); i++ ) + { + if ( g_GamePaths[i].appId == nAppId ) + { + pGameToMount = &g_GamePaths[i]; + break; + } + } + + if ( !pGameToMount ) + { + Warning( "Failed to mount content for game with AppID: %i (game not found)\n", nAppId ); + return false; + } + + KeyValues *pMainFile, *pFileSystemInfo; + pMainFile = new KeyValues( "gamecontent.txt" ); + +#ifdef CLIENT_DLL + const char *gamePath = engine->GetGameDirectory(); +#else + char gamePath[256]; + engine->GetGameDir( gamePath, 256 ); + Q_StripTrailingSlash( gamePath ); +#endif + + // On linux because of case sensitiviy we need to check for both. + const char *paths[] = { +#ifdef _LINUX + "%s/GameContent.txt", +#endif + "%s/gamecontent.txt" }; + + bool bFound = false; + + for ( int i = 0; i < ARRAYSIZE( paths ); i++ ) + { + if ( !pMainFile->LoadFromFile( filesystem, UTIL_VarArgs( paths[i], gamePath ), CONTENT_SEARCH_PATH ) ) + continue; + + pFileSystemInfo = pMainFile->FindKey( "FileSystem" ); + + if ( !pFileSystemInfo ) + continue; + + pFileSystemInfo->SetInt( pGameToMount->directoryName, pGameToMount->appId ); + + pMainFile->SaveToFile( filesystem, UTIL_VarArgs( paths[i], gamePath ), CONTENT_SEARCH_PATH ); + bFound = true; + + // We've found the game, no need to continue searching. + break; + } + + pMainFile->deleteThis(); + + if ( !bFound ) + { + Warning( "Failed to mount content for game %s (GameContent.txt not found)\n", pGameToMount->name ); + return false; + } + + AddSearchPathByAppId( pGameToMount->appId ); + return true; +} + +bool UnmountGameContentByAppId( int nAppId ) +{ + mountableGame_t *pGameToUnmount = nullptr; + + for ( int i = 0; i < g_GamePaths.Count(); i++ ) + { + if ( g_GamePaths[i].appId == nAppId ) + { + pGameToUnmount = &g_GamePaths[i]; + break; + } + } + + if ( !pGameToUnmount ) + { + Warning( "Failed to unmount content for game with AppID: %i (game not found)\n", nAppId ); + return false; + } + + KeyValues *pMainFile, *pFileSystemInfo; + pMainFile = new KeyValues( "gamecontent.txt" ); + + #ifdef CLIENT_DLL + const char *gamePath = engine->GetGameDirectory(); + #else + char gamePath[256]; + engine->GetGameDir( gamePath, 256 ); + Q_StripTrailingSlash( gamePath ); + #endif + + // On linux because of case sensitiviy we need to check for both. + const char *paths[] = { + #ifdef _LINUX + "%s/GameContent.txt", + #endif + "%s/gamecontent.txt" }; + + bool bFound = false; + + for ( int i = 0; i < ARRAYSIZE( paths ); i++ ) + { + if ( !pMainFile->LoadFromFile( filesystem, UTIL_VarArgs( paths[i], gamePath ), CONTENT_SEARCH_PATH ) ) + continue; + + pFileSystemInfo = pMainFile->FindKey( "FileSystem" ); + + if ( !pFileSystemInfo ) + continue; + + KeyValues *pSubKey = pFileSystemInfo->FindKey( pGameToUnmount->directoryName ); + pFileSystemInfo->RemoveSubKey( pSubKey ); + + pMainFile->SaveToFile( filesystem, UTIL_VarArgs( paths[i], gamePath ), CONTENT_SEARCH_PATH ); + bFound = true; + + // We've found the game, no need to continue searching. + break; + } + + pMainFile->deleteThis(); + + if ( !bFound ) + { + Warning( "Failed to unmount content for game %s (GameContent.txt not found)\n", pGameToUnmount->name ); + return false; + } + + RemoveSearchPathByAppId( pGameToUnmount->appId ); + + return true; +} diff --git a/src/game/shared/mountsteamcontent.h b/src/game/shared/mountsteamcontent.h index f3d6834f20..ced991542a 100644 --- a/src/game/shared/mountsteamcontent.h +++ b/src/game/shared/mountsteamcontent.h @@ -11,6 +11,58 @@ #pragma once #endif -void MountUserContent(); +struct mountableGame_t +{ + // Directory inside the game's root directory where the game's content is stored + // e.g: garrysmod, cstrike, hl2 + const char *directoryName; + + // The Steam AppID of the game + int appId; + + // The human-readable name of the game + const char *name; + + // Paths to VPK files that should be mounted + CUtlVector< const char * > vpks; + + bool isMounted; + bool isOwned; + bool isInstalled; + + mountableGame_t( const char *gameName, const char *directoryName, int gameId, bool isInstalled, bool isOwned ) + : name( gameName ), + directoryName( directoryName ), + appId( gameId ), + isMounted( false ), + isOwned( isOwned ), + isInstalled( isInstalled ) + { + } + + mountableGame_t( const mountableGame_t &other ) + : name( other.name ), + directoryName( other.directoryName ), + appId( other.appId ), + isMounted( other.isMounted ), + isOwned( other.isOwned ), + isInstalled( other.isInstalled ) + { + for ( int i = 0; i < other.vpks.Count(); i++ ) + { + vpks.AddToTail( other.vpks[i] ); + } + } + + void AddVPK( const char *vpkPath ) + { + vpks.AddToTail( vpkPath ); + } +}; + +void InitializeGameContentMounting(); +bool MountGameContentByAppId( int nAppId ); +bool UnmountGameContentByAppId( int nAppId ); +CUtlVector< mountableGame_t > &GetMountableGames(); #endif // MOUNTSTEAMCONTENT_H diff --git a/src/lib/public/tier1.lib b/src/lib/public/tier1.lib index afa4d4a363..a3a1479121 100644 --- a/src/lib/public/tier1.lib +++ b/src/lib/public/tier1.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:edbfc8b0bc42291a39a6769d5d0929898917618277ca8585ba21ea6b7a7b503e -size 4694178 +oid sha256:3bcbd48fa03f414fb16641c84bd22bc5a466b03baeed7f4bd41cf1d9d2c6b952 +size 4694814 diff --git a/src/lib/public/vgui_controls.lib b/src/lib/public/vgui_controls.lib index 8a1d7cd314..ee4d9fb18c 100644 --- a/src/lib/public/vgui_controls.lib +++ b/src/lib/public/vgui_controls.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72613ef7b535161a9988c823f1235a21fe91236897c86cc5491ba7142c271d5d -size 19481116 +oid sha256:700de62224899a3b880e08c7f9588a75898e4af339dd72be7e7e5702d09a33cd +size 19481222 diff --git a/src/public/lcdll_int.cpp b/src/public/lcdll_int.cpp index 81ebfa6eb4..21d95ec878 100644 --- a/src/public/lcdll_int.cpp +++ b/src/public/lcdll_int.cpp @@ -22,12 +22,6 @@ static int engine_ActivateOccluder( lua_State *L ) return 0; } -static int engine_ChangeTeam( lua_State *L ) -{ - engine->ChangeTeam( luaL_checkstring( L, 1 ) ); - return 0; -} - static int engine_CheckKeyTrapping( lua_State *L ) { ButtonCode_t code; @@ -137,12 +131,6 @@ static int engine_GameLumpVersion( lua_State *L ) return 1; } -static int engine_GetAppID( lua_State *L ) -{ - lua_pushinteger( L, engine->GetAppID() ); - return 1; -} - static int engine_GetClientConVarValue( lua_State *L ) { int iPlayer; @@ -218,24 +206,6 @@ static int engine_GetLastTimeStamp( lua_State *L ) return 1; } -static int engine_GetServerAddress( lua_State *L ) -{ - lua_pushstring( L, g_pGameInfoStore->GetServerAddress() ); - return 1; -} - -static int engine_GetServerName( lua_State *L ) -{ - lua_pushstring( L, g_pGameInfoStore->GetServerName() ); - return 1; -} - -static int engine_GetLevelName( lua_State *L ) -{ - lua_pushstring( L, engine->GetLevelName() ); - return 1; -} - static int engine_GetLightForPoint( lua_State *L ) { Vector v = engine->GetLightForPoint( luaL_checkvector( L, 1 ), luaL_checkboolean( L, 2 ) ); @@ -264,12 +234,6 @@ static int engine_GetMainMenuBackgroundName( lua_State *L ) return 1; } -static int engine_GetMapEntitiesString( lua_State *L ) -{ - lua_pushstring( L, engine->GetMapEntitiesString() ); - return 1; -} - static int engine_GetMaxClients( lua_State *L ) { lua_pushinteger( L, engine->GetMaxClients() ); @@ -388,12 +352,6 @@ static int engine_IsHLTV( lua_State *L ) return 1; } -static int engine_IsInEditMode( lua_State *L ) -{ - lua_pushboolean( L, engine->IsInEditMode() ); - return 1; -} - static int engine_IsInGame( lua_State *L ) { lua_pushboolean( L, engine->IsInGame() ); @@ -406,24 +364,12 @@ static int engine_IsLevelMainMenuBackground( lua_State *L ) return 1; } -static int engine_IsLowViolence( lua_State *L ) -{ - lua_pushboolean( L, engine->IsLowViolence() ); - return 1; -} - static int engine_IsOccluded( lua_State *L ) { luaL_checkboolean( L, engine->IsOccluded( luaL_checkvector( L, 1 ), luaL_checkvector( L, 2 ) ) ); return 1; } -static int engine_IsPaused( lua_State *L ) -{ - lua_pushboolean( L, engine->IsPaused() ); - return 1; -} - static int engine_IsPlayingDemo( lua_State *L ) { lua_pushboolean( L, engine->IsPlayingDemo() ); @@ -512,36 +458,6 @@ static int engine_ResetDemoInterpolation( lua_State *L ) return 0; } -static int engine_SentenceGroupIndexFromName( lua_State *L ) -{ - lua_pushinteger( L, engine->SentenceGroupIndexFromName( luaL_checkstring( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceGroupNameFromIndex( lua_State *L ) -{ - lua_pushstring( L, engine->SentenceGroupNameFromIndex( luaL_checknumber( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceIndexFromName( lua_State *L ) -{ - lua_pushinteger( L, engine->SentenceIndexFromName( luaL_checkstring( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceLength( lua_State *L ) -{ - lua_pushnumber( L, engine->SentenceLength( luaL_checknumber( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceNameFromIndex( lua_State *L ) -{ - lua_pushstring( L, engine->SentenceNameFromIndex( luaL_checknumber( L, 1 ) ) ); - return 1; -} - static int engine_ServerCmd( lua_State *L ) { engine->ServerCmd( luaL_checkstring( L, 1 ), luaL_checkboolean( L, 2 ) ); @@ -584,15 +500,8 @@ static int engine_SupportsHDR( lua_State *L ) return 1; } -static int engine_Time( lua_State *L ) -{ - lua_pushnumber( L, engine->Time() ); - return 1; -} - static const luaL_Reg enginelib[] = { { "ActivateOccluder", engine_ActivateOccluder }, - { "ChangeTeam", engine_ChangeTeam }, { "CheckKeyTrapping", engine_CheckKeyTrapping }, { "IsKeyTrapping", engine_IsKeyTrapping }, @@ -609,21 +518,16 @@ static const luaL_Reg enginelib[] = { { "EngineStats_BeginFrame", engine_EngineStats_BeginFrame }, { "EngineStats_EndFrame", engine_EngineStats_EndFrame }, { "GameLumpSize", engine_GameLumpSize }, - { "GetAppID", engine_GetAppID }, { "GetClientConVarValue", engine_GetClientConVarValue }, { "GetClientConVarValueAsNumber", engine_GetClientConVarValueAsNumber }, { "GetDXSupportLevel", engine_GetDXSupportLevel }, { "GetEngineBuildNumber", engine_GetEngineBuildNumber }, { "GetGameDirectory", engine_GetGameDirectory }, { "GetLastTimeStamp", engine_GetLastTimeStamp }, - { "GetServerAddress", engine_GetServerAddress }, - { "GetServerName", engine_GetServerName }, - { "GetLevelName", engine_GetLevelName }, { "GetLightForPoint", engine_GetLightForPoint }, { "GetLightForPointFast", engine_GetLightForPointFast }, { "GetLocalPlayer", engine_GetLocalPlayer }, { "GetMainMenuBackgroundName", engine_GetMainMenuBackgroundName }, - { "GetMapEntitiesString", engine_GetMapEntitiesString }, { "GetMaxClients", engine_GetMaxClients }, { "GetMostRecentSaveGame", engine_GetMostRecentSaveGame }, { "GetPlayerForUserID", engine_GetPlayerForUserID }, @@ -639,12 +543,9 @@ static const luaL_Reg enginelib[] = { { "IsDrawingLoadingImage", engine_IsDrawingLoadingImage }, { "IsHammerRunning", engine_IsHammerRunning }, { "IsHLTV", engine_IsHLTV }, - { "IsInEditMode", engine_IsInEditMode }, { "IsInGame", engine_IsInGame }, { "IsLevelMainMenuBackground", engine_IsLevelMainMenuBackground }, - { "IsLowViolence", engine_IsLowViolence }, { "IsOccluded", engine_IsOccluded }, - { "IsPaused", engine_IsPaused }, { "IsPlayingDemo", engine_IsPlayingDemo }, { "IsPlayingTimeDemo", engine_IsPlayingTimeDemo }, { "IsRecordingDemo", engine_IsRecordingDemo }, @@ -659,11 +560,6 @@ static const luaL_Reg enginelib[] = { { "OnStorageDeviceDetached", engine_OnStorageDeviceDetached }, { "REMOVED_SteamProcessCall", engine_REMOVED_SteamProcessCall }, { "ResetDemoInterpolation", engine_ResetDemoInterpolation }, - { "SentenceGroupIndexFromName", engine_SentenceGroupIndexFromName }, - { "SentenceGroupNameFromIndex", engine_SentenceGroupNameFromIndex }, - { "SentenceIndexFromName", engine_SentenceIndexFromName }, - { "SentenceLength", engine_SentenceLength }, - { "SentenceNameFromIndex", engine_SentenceNameFromIndex }, { "ServerCmd", engine_ServerCmd }, { "SetMapLoadFailed", engine_SetMapLoadFailed }, { "SetRestrictClientCommands", engine_SetRestrictClientCommands }, @@ -671,7 +567,6 @@ static const luaL_Reg enginelib[] = { { "Sound_ExtraUpdate", engine_Sound_ExtraUpdate }, { "StartXboxExitingProcess", engine_StartXboxExitingProcess }, { "SupportsHDR", engine_SupportsHDR }, - { "Time", engine_Time }, { NULL, NULL } }; /* diff --git a/src/public/leiface.cpp b/src/public/lengine.cpp similarity index 71% rename from src/public/leiface.cpp rename to src/public/lengine.cpp index d0b2c639f6..e2b9691c1d 100644 --- a/src/public/leiface.cpp +++ b/src/public/lengine.cpp @@ -35,12 +35,6 @@ static int engine_ChangeLevel( lua_State *L ) return 0; } -static int engine_ChangeTeam( lua_State *L ) -{ - engine->ChangeTeam( luaL_checkstring( L, 1 ) ); - return 0; -} - static int engine_CheckAreasConnected( lua_State *L ) { lua_pushinteger( L, engine->CheckAreasConnected( luaL_checkinteger( L, 1 ), luaL_checkinteger( L, 2 ) ) ); @@ -80,12 +74,6 @@ static int engine_ForceSimpleMaterial( lua_State *L ) return 0; } -static int engine_GetAppID( lua_State *L ) -{ - lua_pushinteger( L, engine->GetAppID() ); - return 1; -} - static int engine_GetClientConVarValue( lua_State *L ) { int iPlayer; @@ -118,53 +106,6 @@ static int engine_GetEntityCount( lua_State *L ) return 1; } -static int engine_GetServerAddress( lua_State *L ) -{ - lua_pushstring( L, g_pGameInfoStore->GetServerAddress() ); - return 1; -} - -static int engine_GetServerName( lua_State *L ) -{ - lua_pushstring( L, g_pGameInfoStore->GetServerName() ); - return 1; -} - -static int engine_GetLevelName( lua_State *L ) -{ - char szMap[MAX_PATH + 1] = ""; - Q_strncpy( szMap, gpGlobals->mapname.ToCStr(), ARRAYSIZE( szMap ) ); - lua_pushstring( L, szMap ); - return 1; -} - -static int engine_GetPlayerByAddress( lua_State *L ) -{ - CBasePlayer *pPlayer = g_pGameInfoStore->GetPlayerByAddress( luaL_checkstring( L, 1 ) ); - - if ( pPlayer ) - { - CBaseEntity::PushLuaInstanceSafe( L, pPlayer ); - return 1; - } - - return 0; -} - -static int engine_GetGameDir( lua_State *L ) -{ - char gamePath[256]; - engine->GetGameDir( gamePath, 256 ); - lua_pushstring( L, gamePath ); - return 1; -} - -static int engine_GetMapEntitiesString( lua_State *L ) -{ - lua_pushstring( L, engine->GetMapEntitiesString() ); - return 1; -} - static int engine_GetMostRecentlyLoadedFileName( lua_State *L ) { lua_pushstring( L, engine->GetMostRecentlyLoadedFileName() ); @@ -219,24 +160,12 @@ static int engine_IsInCommentaryMode( lua_State *L ) return 1; } -static int engine_IsInEditMode( lua_State *L ) -{ - lua_pushinteger( L, engine->IsInEditMode() ); - return 1; -} - static int engine_IsInternalBuild( lua_State *L ) { lua_pushboolean( L, engine->IsInternalBuild() ); return 1; } -static int engine_IsLowViolence( lua_State *L ) -{ - lua_pushboolean( L, engine->IsLowViolence() ); - return 1; -} - static int engine_IsMapValid( lua_State *L ) { lua_pushinteger( L, engine->IsMapValid( luaL_checkstring( L, 1 ) ) ); @@ -249,12 +178,6 @@ static int engine_IsModelPrecached( lua_State *L ) return 1; } -static int engine_IsPaused( lua_State *L ) -{ - lua_pushboolean( L, engine->IsPaused() ); - return 1; -} - static int engine_LightStyle( lua_State *L ) { engine->LightStyle( luaL_checkinteger( L, 1 ), luaL_checkstring( L, 2 ) ); @@ -321,36 +244,6 @@ static int engine_PrecacheSentenceFile( lua_State *L ) return 1; } -static int engine_SentenceGroupIndexFromName( lua_State *L ) -{ - lua_pushinteger( L, engine->SentenceGroupIndexFromName( luaL_checkstring( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceGroupNameFromIndex( lua_State *L ) -{ - lua_pushstring( L, engine->SentenceGroupNameFromIndex( luaL_checkinteger( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceIndexFromName( lua_State *L ) -{ - lua_pushinteger( L, engine->SentenceIndexFromName( luaL_checkstring( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceLength( lua_State *L ) -{ - lua_pushnumber( L, engine->SentenceLength( luaL_checkinteger( L, 1 ) ) ); - return 1; -} - -static int engine_SentenceNameFromIndex( lua_State *L ) -{ - lua_pushstring( L, engine->SentenceNameFromIndex( luaL_checkinteger( L, 1 ) ) ); - return 1; -} - static int engine_ServerCommand( lua_State *L ) { const char *pszCommandString = luaL_checkstring( L, 1 ); @@ -380,38 +273,17 @@ static int engine_SetDedicatedServerBenchmarkMode( lua_State *L ) return 0; } -static int engine_Time( lua_State *L ) -{ - lua_pushnumber( L, engine->Time() ); - return 1; -} - -static int engine_GetSoundDuration( lua_State *L ) -{ - float flDuration = enginesound->GetSoundDuration( luaL_checkstring( L, 1 ) ); - lua_pushnumber( L, flDuration ); - return 1; -} - static const luaL_Reg enginelib[] = { { "AllowImmediateEdictReuse", engine_AllowImmediateEdictReuse }, { "ChangeLevel", engine_ChangeLevel }, - { "ChangeTeam", engine_ChangeTeam }, { "CheckAreasConnected", engine_CheckAreasConnected }, { "CopyFile", engine_CopyFile }, { "CreateFakeClient", engine_CreateFakeClient }, { "ForceExactFile", engine_ForceExactFile }, { "ForceSimpleMaterial", engine_ForceSimpleMaterial }, - { "GetAppID", engine_GetAppID }, { "GetClientConVarValue", engine_GetClientConVarValue }, { "GetClientConVarValueAsNumber", engine_GetClientConVarValueAsNumber }, { "GetEntityCount", engine_GetEntityCount }, - { "GetServerAddress", engine_GetServerAddress }, - { "GetServerName", engine_GetServerName }, - { "GetLevelName", engine_GetLevelName }, - { "GetPlayerByAddress", engine_GetPlayerByAddress }, - { "GetGameDir", engine_GetGameDir }, - { "GetMapEntitiesString", engine_GetMapEntitiesString }, { "GetMostRecentlyLoadedFileName", engine_GetMostRecentlyLoadedFileName }, { "GetPlayerNetInfo", engine_GetPlayerNetInfo }, { "GetSaveFileName", engine_GetSaveFileName }, @@ -421,12 +293,9 @@ static const luaL_Reg enginelib[] = { { "IsDedicatedServer", engine_IsDedicatedServer }, { "IsGenericPrecached", engine_IsGenericPrecached }, { "IsInCommentaryMode", engine_IsInCommentaryMode }, - { "IsInEditMode", engine_IsInEditMode }, { "IsInternalBuild", engine_IsInternalBuild }, - { "IsLowViolence", engine_IsLowViolence }, { "IsMapValid", engine_IsMapValid }, { "IsModelPrecached", engine_IsModelPrecached }, - { "IsPaused", engine_IsPaused }, { "LoadAdjacentEnts", engine_LoadAdjacentEnts }, { "LoadGameState", engine_LoadGameState }, { "LockNetworkStringTables", engine_LockNetworkStringTables }, @@ -437,17 +306,10 @@ static const luaL_Reg enginelib[] = { { "PrecacheGeneric", engine_PrecacheGeneric }, { "PrecacheModel", engine_PrecacheModel }, { "PrecacheSentenceFile", engine_PrecacheSentenceFile }, - { "SentenceGroupIndexFromName", engine_SentenceGroupIndexFromName }, - { "SentenceGroupNameFromIndex", engine_SentenceGroupNameFromIndex }, - { "SentenceIndexFromName", engine_SentenceIndexFromName }, - { "SentenceLength", engine_SentenceLength }, - { "SentenceNameFromIndex", engine_SentenceNameFromIndex }, { "ServerCommand", engine_ServerCommand }, { "ServerExecute", engine_ServerExecute }, { "SetAreaPortalState", engine_SetAreaPortalState }, { "SetDedicatedServerBenchmarkMode", engine_SetDedicatedServerBenchmarkMode }, - { "Time", engine_Time }, - { "GetSoundDuration", engine_GetSoundDuration }, { NULL, NULL } }; /* diff --git a/src/public/lengine_shared.cpp b/src/public/lengine_shared.cpp new file mode 100644 index 0000000000..00762bc777 --- /dev/null +++ b/src/public/lengine_shared.cpp @@ -0,0 +1,216 @@ +#include "cbase.h" +#include "luamanager.h" +#include "luasrclib.h" +#include "lbaseentity_shared.h" +#include "lbaseplayer_shared.h" +#include "linetchannelinfo.h" +#include "engine/IEngineSound.h" +#include +#include +#include + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" +#include + +static int engine_ChangeTeam( lua_State *L ) +{ + engine->ChangeTeam( luaL_checkstring( L, 1 ) ); + return 0; +} + +static int engine_GetAppID( lua_State *L ) +{ + lua_pushinteger( L, engine->GetAppID() ); + return 1; +} + +static int engine_GetServerAddress( lua_State *L ) +{ + lua_pushstring( L, g_pGameInfoStore->GetServerAddress() ); + return 1; +} + +static int engine_GetServerName( lua_State *L ) +{ + lua_pushstring( L, g_pGameInfoStore->GetServerName() ); + return 1; +} + +static int engine_GetLevelName( lua_State *L ) +{ +#ifdef CLIENT_DLL + lua_pushstring( L, engine->GetLevelName() ); +#else + char szMap[MAX_PATH + 1] = ""; + Q_strncpy( szMap, gpGlobals->mapname.ToCStr(), ARRAYSIZE( szMap ) ); + lua_pushstring( L, szMap ); +#endif + return 1; +} + +static int engine_GetPlayerByAddress( lua_State *L ) +{ + CBasePlayer *pPlayer = g_pGameInfoStore->GetPlayerByAddress( luaL_checkstring( L, 1 ) ); + + if ( pPlayer ) + { + CBaseEntity::PushLuaInstanceSafe( L, pPlayer ); + return 1; + } + + return 0; +} + +static int engine_GetGameDir( lua_State *L ) +{ +#ifdef CLIENT_DLL + const char *gamePath = engine->GetGameDirectory(); +#else + char gamePath[MAX_PATH]; + engine->GetGameDir( gamePath, MAX_PATH ); + Q_StripTrailingSlash( gamePath ); +#endif + lua_pushstring( L, gamePath ); + + return 1; +} + +static int engine_GetMapEntitiesString( lua_State *L ) +{ + lua_pushstring( L, engine->GetMapEntitiesString() ); + return 1; +} + +static int engine_GetMountableGames( lua_State *L ) +{ + lua_newtable( L ); + + CUtlVector< mountableGame_t > &mountableGames = GetMountableGames(); + + for ( int i = 0; i < mountableGames.Count(); i++ ) + { + lua_pushinteger( L, i + 1 ); + lua_newtable( L ); + + lua_pushstring( L, "name" ); + lua_pushstring( L, mountableGames[i].name ); + lua_settable( L, -3 ); + + lua_pushstring( L, "directoryName" ); + lua_pushstring( L, mountableGames[i].directoryName ); + lua_settable( L, -3 ); + + lua_pushstring( L, "isMounted" ); + lua_pushboolean( L, mountableGames[i].isMounted ); + lua_settable( L, -3 ); + + lua_pushstring( L, "isOwned" ); + lua_pushboolean( L, mountableGames[i].isOwned ); + lua_settable( L, -3 ); + + lua_pushstring( L, "isInstalled" ); + lua_pushboolean( L, mountableGames[i].isInstalled ); + lua_settable( L, -3 ); + + lua_pushstring( L, "appId" ); + lua_pushinteger( L, mountableGames[i].appId ); + lua_settable( L, -3 ); + + lua_settable( L, -3 ); + } + + return 1; +} + +static int engine_IsInEditMode( lua_State *L ) +{ + lua_pushinteger( L, engine->IsInEditMode() ); + return 1; +} + +static int engine_IsLowViolence( lua_State *L ) +{ + lua_pushboolean( L, engine->IsLowViolence() ); + return 1; +} + +static int engine_IsPaused( lua_State *L ) +{ + lua_pushboolean( L, engine->IsPaused() ); + return 1; +} + +static int engine_SentenceGroupIndexFromName( lua_State *L ) +{ + lua_pushinteger( L, engine->SentenceGroupIndexFromName( luaL_checkstring( L, 1 ) ) ); + return 1; +} + +static int engine_SentenceGroupNameFromIndex( lua_State *L ) +{ + lua_pushstring( L, engine->SentenceGroupNameFromIndex( luaL_checkinteger( L, 1 ) ) ); + return 1; +} + +static int engine_SentenceIndexFromName( lua_State *L ) +{ + lua_pushinteger( L, engine->SentenceIndexFromName( luaL_checkstring( L, 1 ) ) ); + return 1; +} + +static int engine_SentenceLength( lua_State *L ) +{ + lua_pushnumber( L, engine->SentenceLength( luaL_checkinteger( L, 1 ) ) ); + return 1; +} + +static int engine_SentenceNameFromIndex( lua_State *L ) +{ + lua_pushstring( L, engine->SentenceNameFromIndex( luaL_checkinteger( L, 1 ) ) ); + return 1; +} + +static int engine_Time( lua_State *L ) +{ + lua_pushnumber( L, engine->Time() ); + return 1; +} + +static int engine_GetSoundDuration( lua_State *L ) +{ + float flDuration = enginesound->GetSoundDuration( luaL_checkstring( L, 1 ) ); + lua_pushnumber( L, flDuration ); + return 1; +} + +static const luaL_Reg enginelib[] = { + { "ChangeTeam", engine_ChangeTeam }, + { "GetAppID", engine_GetAppID }, + { "GetServerAddress", engine_GetServerAddress }, + { "GetServerName", engine_GetServerName }, + { "GetLevelName", engine_GetLevelName }, + { "GetPlayerByAddress", engine_GetPlayerByAddress }, + { "GetGameDir", engine_GetGameDir }, + { "GetMapEntitiesString", engine_GetMapEntitiesString }, + { "GetMountableGames", engine_GetMountableGames }, + { "IsInEditMode", engine_IsInEditMode }, + { "IsLowViolence", engine_IsLowViolence }, + { "IsPaused", engine_IsPaused }, + { "SentenceGroupIndexFromName", engine_SentenceGroupIndexFromName }, + { "SentenceGroupNameFromIndex", engine_SentenceGroupNameFromIndex }, + { "SentenceIndexFromName", engine_SentenceIndexFromName }, + { "SentenceLength", engine_SentenceLength }, + { "SentenceNameFromIndex", engine_SentenceNameFromIndex }, + { "Time", engine_Time }, + { "GetSoundDuration", engine_GetSoundDuration }, + { NULL, NULL } }; + +/* +** Open engine library +*/ +LUALIB_API int luaopen_engine_shared( lua_State *L ) +{ + luaL_register( L, LUA_ENGINELIBNAME, enginelib ); + return 1; +} diff --git a/src/public/tier1/KeyValues.h b/src/public/tier1/KeyValues.h index 97ae69c23e..bf09e4a406 100644 --- a/src/public/tier1/KeyValues.h +++ b/src/public/tier1/KeyValues.h @@ -134,6 +134,7 @@ class KeyValues KeyValues *FindKey(const char *keyName, bool bCreate = false); KeyValues *FindKey(int keySymbol) const; KeyValues *CreateNewKey(); // creates a new key, with an autogenerated name. name is guaranteed to be an integer, of value 1 higher than the highest other integer key name + KeyValues *GetNextKeyName( char *newKeyName, int newKeyNameBufferSize ); void AddSubKey( KeyValues *pSubkey ); // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues void RemoveSubKey(KeyValues *subKey); // removes a subkey from the list, DOES NOT DELETE IT diff --git a/src/tier1/KeyValues.cpp b/src/tier1/KeyValues.cpp index 7152950946..8559e836ab 100644 --- a/src/tier1/KeyValues.cpp +++ b/src/tier1/KeyValues.cpp @@ -1085,10 +1085,18 @@ KeyValues *KeyValues::FindKey( const char *keyName, bool bCreate ) //----------------------------------------------------------------------------- KeyValues *KeyValues::CreateNewKey() { + char buf[12]; + KeyValues *pLastChild = GetNextKeyName( buf, sizeof( buf ) ); + + return CreateKeyUsingKnownLastChild( buf, pLastChild ); +} + +KeyValues *KeyValues::GetNextKeyName( char *newKeyName, int newKeyNameBufferSize ) +{ + KeyValues *pLastChild = NULL; int newID = 1; // search for any key with higher values - KeyValues *pLastChild = NULL; for ( KeyValues *dat = m_pSub; dat != NULL; dat = dat->m_pPeer ) { // case-insensitive string compare @@ -1101,10 +1109,9 @@ KeyValues *KeyValues::CreateNewKey() pLastChild = dat; } - char buf[12]; - Q_snprintf( buf, sizeof( buf ), "%d", newID ); + Q_snprintf( newKeyName, newKeyNameBufferSize, "%d", newID ); - return CreateKeyUsingKnownLastChild( buf, pLastChild ); + return pLastChild; } //----------------------------------------------------------------------------- diff --git a/src/vgui2/vgui_controls/HTML.cpp b/src/vgui2/vgui_controls/HTML.cpp index 7da70c3e95..56d1b3b697 100644 --- a/src/vgui2/vgui_controls/HTML.cpp +++ b/src/vgui2/vgui_controls/HTML.cpp @@ -342,6 +342,7 @@ void HTML::AddJavascriptObjectCallback( const char *pszObjectName, const char *p " args = Array.prototype.slice.call(arguments); " " } " " let __cId = window.g_Interop.__callbackQueue.push(callback)-1; " + " console.log('Callback ID: ' + __cId + ' with args: ' + JSON.stringify(args)); " " alert('%s' + JSON.stringify({object:'%s',property:'%s',arguments:args,callbackId:__cId})); " "}; ", pszObjectName, @@ -367,7 +368,7 @@ void HTML::CallJavascriptObjectCallback( int callbackId, KeyValues *args ) CJsonToKeyValues::ConvertKeyValuesToJson( args, szJson, sizeof( szJson ) ); char szScript[8096]; - Q_snprintf( szScript, sizeof( szScript ), "if (typeof window.g_Interop.__callbackQueue[%i] === 'function') window.g_Interop.__callbackQueue[%i](%s);", callbackId, callbackId, szJson ); + Q_snprintf( szScript, sizeof( szScript ), "if (typeof window.g_Interop.__callbackQueue[%i] === 'function') window.g_Interop.__callbackQueue[%i].apply(null, Object.values(%s));", callbackId, callbackId, szJson ); m_SteamAPIContext.SteamHTMLSurface()->ExecuteJavascript( m_unBrowserHandle, szScript ); } @@ -380,11 +381,14 @@ void HTML::OnJavaScriptCallback( KeyValues *pData ) { // const char *pszObject = pData->GetString( "object" ); // const char *pszProperty = pData->GetString( "property" ); + //KeyValues *pArguments = pData->FindKey( "arguments" ); - // for ( KeyValues *pArg = pData->FindKey( "arguments" ); pArg; pArg = pArg->GetNextKey() ) + //for ( KeyValues *pArg = pArguments->GetFirstSubKey(); pArg; pArg = pArg->GetNextKey() ) //{ - // DevMsg( "Argument: %s (inside %s.%s call)\n", pArg->GetName(), pszObject, pszProperty ); - // } + // lua_pushstring( L, pArg->GetName() ); + // lua_pushstring( L, pArg->GetString() ); + // lua_settable( L, -3 ); + //} } ///