diff --git a/lua/autorun/streamradio_loader.lua b/lua/autorun/streamradio_loader.lua index d66aa69..e581a35 100644 --- a/lua/autorun/streamradio_loader.lua +++ b/lua/autorun/streamradio_loader.lua @@ -486,14 +486,14 @@ end local outdated = false if CLIENT then - if Gmodversion < 220608 and Gmodversion > 5 then + if Gmodversion < 220713 and Gmodversion > 5 then StreamRadioLib.ErrorString = "Your GMod-Client (Version: " .. Gmodversion .. ") is too old!\nPlease update the GMod-Client!" outdated = true ErrorNoHalt(AddonPrefix .. StreamRadioLib.ErrorString .. "\n") end else - if Gmodversion < 220608 and Gmodversion > 5 then + if Gmodversion < 220713 and Gmodversion > 5 then StreamRadioLib.ErrorString = "The GMod-Server (Version: " .. Gmodversion .. ") is too old!\nPlease update the GMod-Server!" outdated = true diff --git a/lua/entities/base_streamradio_gui.lua b/lua/entities/base_streamradio_gui.lua index c71066e..31bf28e 100644 --- a/lua/entities/base_streamradio_gui.lua +++ b/lua/entities/base_streamradio_gui.lua @@ -45,25 +45,6 @@ function ENT:GetDisplayPos( ) return pos, ang end -function ENT:CheckPropProtection(ply) - -- Support for prop protections - if self.CPPICanUse then - local use = self:CPPICanUse(ply) or false - if not use then - return false - end - end - - if SERVER then - local use = hook.Run("PlayerUse", ply, radio) - if not use then - return false - end - end - - return true -end - function ENT:CanControlInternal(ply, userEntity) if self:GetDisableInput() then return false end @@ -71,7 +52,7 @@ function ENT:CanControlInternal(ply, userEntity) if self:GetDisableDisplay() then return false end -- Check the player for +use permission - if not self:CheckPropProtection(ply) then + if not StreamRadioLib.CheckPropProtectionAgainstUse(self, ply) then return false end @@ -118,13 +99,22 @@ function ENT:CanControl(ply, userEntity) end local cacheId = tostring(ply) .. "_" .. tostring(userEntity) + local now = RealTime() + + -- cache the check result for a short time to avoid running expensive functions every tick + if self._canControlCacheExpire and self._canControlCacheExpire <= now then + self._canControlCache = nil + self._canControlCacheExpire = nil + end if self._canControlCache and self._canControlCache[cacheId] ~= nil then return self._canControlCache[cacheId] end - self._canControlCache = self._canControlCache or {} - self._canControlCache[cacheId] = nil + if not self._canControlCache then + self._canControlCache = {} + self._canControlCacheExpire = now + 0.25 + end local result = self:CanControlInternal(ply, userEntity) @@ -176,7 +166,11 @@ function ENT:GetCursor( ply, trace, userEntity ) end local scale = self:GetScale() + if scale <= 0 then return false end + local pos, ang = self:GetDisplayPos() + if not pos then return false end + if not ang then return false end local TraceHitPos = util.IntersectRayWithPlane( trace.StartPos, trace.Normal, pos, ang:Up( ) ) @@ -211,7 +205,7 @@ function ENT:CallModelFunction(index, ...) local status, err, a, b, c, d, e, f, g = pcall( self.ModelData[index], self.ModelData, self, ... ) if not status and err then - ErrorNoHalt( err .. "\n" ) + StreamRadioLib.ErrorNoHaltWithStack( err .. "\n" ) return nil end @@ -356,9 +350,6 @@ end function ENT:FastThink() BaseClass.FastThink(self) - - self._canControlCache = {} - self:ControlThink(self:GetLastUser(), self:GetLastUsingEntity()) end diff --git a/lua/entities/sent_streamradio/init.lua b/lua/entities/sent_streamradio/init.lua index 550bbca..284087c 100644 --- a/lua/entities/sent_streamradio/init.lua +++ b/lua/entities/sent_streamradio/init.lua @@ -644,7 +644,7 @@ function ENT:OnWireInputTrigger(name, value, wired) end local delta = math.abs(curtime - value) - local maxDelta = 0.25 + local maxDelta = engine.TickInterval() * 4 if delta < maxDelta then return diff --git a/lua/streamradio_core/api.lua b/lua/streamradio_core/api.lua index 06b06ed..0d05cca 100644 --- a/lua/streamradio_core/api.lua +++ b/lua/streamradio_core/api.lua @@ -77,7 +77,7 @@ local function ErrorCheckArg( var, tright, argn, funcname, level ) local t = type( var ) if t ~= tright then - ErrorNoHaltWithStack( string.format( "bad argument #%i to '%s' (%s or nil expected, got %s)", argn, funcname, tright, t ), level or 3 ) + StreamRadioLib.ErrorNoHaltWithStack( string.format( "bad argument #%i to '%s' (%s or nil expected, got %s)", argn, funcname, tright, t ), level or 3 ) return false end @@ -92,7 +92,7 @@ local function ErrorCheckRadioSettings( settings, argn, funcname, level ) local t = type( v ) local tright = ValidTypes[k] if not tright or t == tright then continue end - ErrorNoHaltWithStack( string.format( "bad datatype at index '%s' of argument #%i at '%s' (%s or nil expected, got %s)", k, argn, funcname, tright, t ), level ) + StreamRadioLib.ErrorNoHaltWithStack( string.format( "bad datatype at index '%s' of argument #%i at '%s' (%s or nil expected, got %s)", k, argn, funcname, tright, t ), level ) return false end @@ -138,7 +138,7 @@ function StreamRadioLib.SpawnRadio( ply, model, pos, ang, settings ) if StreamRadioLib.Msg then StreamRadioLib.Msg( ply, err ) else - ErrorNoHaltWithStack( err, 2 ) + StreamRadioLib.ErrorNoHaltWithStack( err, 2 ) end return diff --git a/lua/streamradio_core/classes/gui_controller.lua b/lua/streamradio_core/classes/gui_controller.lua index 1d72b7f..518afda 100644 --- a/lua/streamradio_core/classes/gui_controller.lua +++ b/lua/streamradio_core/classes/gui_controller.lua @@ -10,7 +10,7 @@ local ColY = Color(255,255,0, 60) local tune_nohdr = Vector( 0.80, 0, 0 ) local CursorMat = StreamRadioLib.GetCustomPNG("cursor") -local catchAndErrorNoHalt = StreamRadioLib.CatchAndErrorNoHalt +local catchAndErrorNoHaltWithStack = StreamRadioLib.CatchAndErrorNoHaltWithStack local g_listengroup = 0 @@ -116,7 +116,7 @@ function CLASS:Create() render.PushFilterMin(TEXFILTER.NONE) render.PushFilterMag(TEXFILTER.NONE) - catchAndErrorNoHalt(self._RenderInternal, self) + catchAndErrorNoHaltWithStack(self._RenderInternal, self) render.PopFilterMag() render.PopFilterMin() @@ -308,13 +308,13 @@ function CLASS:RenderSystem() render.SetToneMappingScaleLinear(tune_nohdr) -- Turns off hdr surface.SetAlphaMultiplier(alpha) - catchAndErrorNoHalt(self.DrawBorder, self) + catchAndErrorNoHaltWithStack(self.DrawBorder, self) surface.SetAlphaMultiplier(1) if self:HasRendertarget() then surface.SetDrawColor(255, 255, 255, alpha * 255) - catchAndErrorNoHalt(self._RT.Render, self._RT) + catchAndErrorNoHaltWithStack(self._RT.Render, self._RT) surface.SetDrawColor(255, 255, 255, 255) self.FrameTime = self._RT:ProfilerTime("Render") @@ -322,14 +322,14 @@ function CLASS:RenderSystem() self:ProfilerStart("Render_rtfallback") surface.SetAlphaMultiplier(alpha) - catchAndErrorNoHalt(self._RenderInternal, self) + catchAndErrorNoHaltWithStack(self._RenderInternal, self) surface.SetAlphaMultiplier(1) self.FrameTime = self:ProfilerEnd("Render_rtfallback") end surface.SetAlphaMultiplier(alpha) - catchAndErrorNoHalt(self.DrawCursor, self) + catchAndErrorNoHaltWithStack(self.DrawCursor, self) surface.SetAlphaMultiplier(1) render.SetToneMappingScaleLinear(oldtune) -- Resets hdr diff --git a/lua/streamradio_core/classes/rendertarget.lua b/lua/streamradio_core/classes/rendertarget.lua index 2044fbe..2e5cab6 100644 --- a/lua/streamradio_core/classes/rendertarget.lua +++ b/lua/streamradio_core/classes/rendertarget.lua @@ -11,7 +11,7 @@ end local BASE = CLASS:GetBaseClass() local g_classname = CLASS:GetClassname() -local catchAndErrorNoHalt = StreamRadioLib.CatchAndErrorNoHalt +local catchAndErrorNoHaltWithStack = StreamRadioLib.CatchAndErrorNoHaltWithStack local g_RenderTargetsCache = CLASS:GetGlobalVar("rendertarget_RenderTargetsCache", {}) @@ -345,7 +345,7 @@ function CLASS:Update() render.PushRenderTarget(self._RT.tex, 0, 0, w, h) render.Clear(0, 0, 0, 0, true) cam.Start2D() - catchAndErrorNoHalt(self.CallHook, self, "OnRender") + catchAndErrorNoHaltWithStack(self.CallHook, self, "OnRender") cam.End2D() render.PopRenderTarget() self:ProfilerEnd("Render") diff --git a/lua/streamradio_core/classes/stream.lua b/lua/streamradio_core/classes/stream.lua index 3675c84..d6a82df 100644 --- a/lua/streamradio_core/classes/stream.lua +++ b/lua/streamradio_core/classes/stream.lua @@ -20,7 +20,7 @@ local SERVER = SERVER local CLIENT = CLIENT local EmptyVector = Vector() -local catchAndErrorNoHalt = StreamRadioLib.CatchAndErrorNoHalt +local catchAndErrorNoHaltWithStack = StreamRadioLib.CatchAndErrorNoHaltWithStack local BASS3 = BASS3 or {} @@ -1235,7 +1235,7 @@ function CLASS:_PlayStreamInternal(URL, URLtype, no3d, noBlock, retrycount) end local safeCallback = function(...) - catchAndErrorNoHalt(callback, ...) + catchAndErrorNoHaltWithStack(callback, ...) end if not URLonline then @@ -1871,6 +1871,7 @@ function CLASS:GetType() end function CLASS:SetVolume( volume ) + if CLIENT then return end if not self.Valid then return end self.Volume.SVMul = volume or 1 end diff --git a/lua/streamradio_core/classes/ui/radio/gui_browser.lua b/lua/streamradio_core/classes/ui/radio/gui_browser.lua index 6529804..1983836 100644 --- a/lua/streamradio_core/classes/ui/radio/gui_browser.lua +++ b/lua/streamradio_core/classes/ui/radio/gui_browser.lua @@ -104,6 +104,11 @@ function CLASS:Create() self.Errorbox:SetNWName("err") self.Errorbox:SetSkinIdentifyer("error") + if IsValid(self.Errorbox.CloseButton) and CLIENT then + -- The error box is handled on the server, so the client shouldn't touch it. + self.Errorbox.CloseButton.DoClick = nil + end + self.Errorbox.OnCloseClick = function() self:GoUpPath() end diff --git a/lua/streamradio_core/classes/ui/radio/gui_player.lua b/lua/streamradio_core/classes/ui/radio/gui_player.lua index 66132cc..a5db65e 100644 --- a/lua/streamradio_core/classes/ui/radio/gui_player.lua +++ b/lua/streamradio_core/classes/ui/radio/gui_player.lua @@ -53,6 +53,7 @@ function CLASS:Create() end self.VolumeBar.OnFractionChangeEdit = function(this, v) + if CLIENT then return end if not IsValid(self.StreamOBJ) then return end self.StreamOBJ:SetVolume(v) end @@ -122,6 +123,10 @@ function CLASS:Create() self.CloseButton:SetSize(200, 60) self.CloseButton:SetText("Back") self.CloseButton.DoClick = function() + if CLIENT then + return + end + if self.State then self.State.Error = 0 end diff --git a/lua/streamradio_core/classes/ui/radio/gui_player_controls.lua b/lua/streamradio_core/classes/ui/radio/gui_player_controls.lua index db167d2..19376c5 100644 --- a/lua/streamradio_core/classes/ui/radio/gui_player_controls.lua +++ b/lua/streamradio_core/classes/ui/radio/gui_player_controls.lua @@ -154,6 +154,7 @@ function CLASS:Create() self.VolumeDownButton:SetSkinIdentifyer("button") self.VolumeDownButton:SetTooltip("Decrease volume") self.VolumeDownButton.OnMousePressed = function() + if CLIENT then return end if not IsValid(self.StreamOBJ) then return end local newvol = self.StreamOBJ:GetVolume() @@ -171,6 +172,7 @@ function CLASS:Create() self.VolumeUpButton:SetSkinIdentifyer("button") self.VolumeUpButton:SetTooltip("Increase volume") self.VolumeUpButton.OnMousePressed = function() + if CLIENT then return end if not IsValid(self.StreamOBJ) then return end local newvol = self.StreamOBJ:GetVolume() @@ -270,13 +272,14 @@ function CLASS:Create() return FormatTimeleft(time, len) end + -- @TODO: fix that seaking is CLIENT -> SERVER instead if SERVER -> CLIENT self.PlayBar.OnFractionChangeEdit = function(this, v) if not IsValid(self.StreamOBJ) then return end local noise = math.random() * 0.00001 local len = self.StreamOBJ:GetMasterLength() - -- Set a fake value that is minimal off target to force a change detection when the right one is set + -- add a minimal noise to the value, so we force the change in any case self.StreamOBJ:SetTime(len * v - noise, true) end @@ -548,6 +551,10 @@ function CLASS:UpdateFromStream() local isEndlessOrNoStream = StreamOBJ:IsEndless() or StreamOBJ:IsLoading() or StreamOBJ:GetError() ~= 0 or StreamOBJ:GetMuted() + -- @TODO: Fix that seaking is CLIENT -> SERVER instead if SERVER -> CLIENT. + -- That's because self.PlayBar is disabled on the server as BASS streams don't exist on servers. + -- Thus these checks below are buggy and will be fixed some day. It is difficult to fix right now. + if IsValid(self.PlayBar) and self.PlayBar:IsVisible() then if isEndlessOrNoStream then self.PlayBar:SetFraction(0) diff --git a/lua/streamradio_core/client/cl_lib.lua b/lua/streamradio_core/client/cl_lib.lua index eaccd2b..c8c4875 100644 --- a/lua/streamradio_core/client/cl_lib.lua +++ b/lua/streamradio_core/client/cl_lib.lua @@ -45,15 +45,18 @@ local g_inRenderScene = false hook.Add( "RenderScene", "Streamradio_CamInfo", function( origin, angles, fov ) if not StreamRadioLib then return end if not StreamRadioLib.Loaded then return end + if not StreamRadioLib.HasSpawnedRadios() then return end + + if g_inRenderScene then return end + g_inRenderScene = true if StreamRadioLib.VR.IsActive() then g_camPos = nil + g_inRenderScene = false + return end - if g_inRenderScene then return end - - g_inRenderScene = true g_camPos = origin g_inRenderScene = false end ) @@ -64,6 +67,7 @@ local g_lastradio = nil local function ReleaseLastRadioControl() if not StreamRadioLib then return end if not StreamRadioLib.Loaded then return end + if not StreamRadioLib.HasSpawnedRadios() then return end local ply = LocalPlayer() if not IsValid( ply ) then return end @@ -133,6 +137,7 @@ end hook.Add("Think", "Streamradio_Control", function( ) if not StreamRadioLib then return end if not StreamRadioLib.Loaded then return end + if not StreamRadioLib.HasSpawnedRadios() then return end local ply = LocalPlayer() if not IsValid( ply ) then return end @@ -265,7 +270,7 @@ do local TestChannel = StreamRadioLib._TestChannel or StreamRadioLib.CreateOBJ("stream") if not IsValid(TestChannel) then - ErrorNoHaltWithStack("Could not create the TestChannel!\n") + StreamRadioLib.ErrorNoHaltWithStack("Could not create the TestChannel!\n") return end diff --git a/lua/streamradio_core/lib.lua b/lua/streamradio_core/lib.lua index af10507..e94a3e9 100644 --- a/lua/streamradio_core/lib.lua +++ b/lua/streamradio_core/lib.lua @@ -69,16 +69,21 @@ function StreamRadioLib.Log(ply, msgstring) MsgN(msgstring) end +function StreamRadioLib.ErrorNoHaltWithStack(err) + err = tostring(err or "") + ErrorNoHaltWithStack(err) +end + local catchAndNohalt = function(err) - local msgstring = err + local msgstring = tostring(err or "") msgstring = string.Trim(StreamRadioLib.AddonPrefix .. msgstring) .. "\n" - ErrorNoHalt(msgstring) + StreamRadioLib.ErrorNoHaltWithStack(err) return err end -function StreamRadioLib.CatchAndErrorNoHalt(func, ...) +function StreamRadioLib.CatchAndErrorNoHaltWithStack(func, ...) return xpcall(func, catchAndNohalt, ...) end @@ -111,7 +116,7 @@ end function StreamRadioLib.Hash(str) str = tostring(str or "") - local salt = "StreamRadioLib_Hash230603" + local salt = "StreamRadioLib_Hash230609" local data = string.format( "[%s][%s]", @@ -329,7 +334,7 @@ function StreamRadioLib.IsSameFrame(id) -- prevent the cache from overflowing if g_LastFrameRegisterCount > 1024 then - g_LastFrameRegister = {} + table.Empty(g_LastFrameRegister) g_LastFrameRegisterCount = 0 end @@ -506,7 +511,7 @@ function StreamRadioLib.Trace(ent) -- prevent the cache from overflowing if g_PlayerTraceCacheCount > 1024 then - g_PlayerTraceCache = {} + table.Empty(g_PlayerTraceCache) g_PlayerTraceCacheCount = 0 end @@ -701,6 +706,77 @@ local function ReleaseLastRadioControl(ply, trace, userEntity) LastRadio:Control( ply, trace, false, userEntity ) end +local g_checkPropProtectionCache = {} +local g_checkPropProtectionCacheEmpty = true +local g_checkPropProtectionCacheExpire = nil + +local function ClearCheckPropProtectionCache() + if g_checkPropProtectionCacheEmpty then + return + end + + table.Empty(g_checkPropProtectionCache) + + g_checkPropProtectionCacheEmpty = true + g_checkPropProtectionCacheExpire = nil +end + +function StreamRadioLib.CheckPropProtectionAgainstUse(ent, ply) + if not IsValid( ent ) then return false end + if not IsValid( ply ) then return false end + + if CLIENT and not ent.CPPICanUse then + return true + end + + local cacheId = tostring(ent) .. "_" .. tostring(ply) + local now = RealTime() + + -- cache the check result for a short time to avoid spam calling the hook "PlayerUse" and CPPI + if g_checkPropProtectionCacheExpire and g_checkPropProtectionCacheExpire <= now then + ClearCheckPropProtectionCache() + end + + if g_checkPropProtectionCache[cacheId] ~= nil then + return g_checkPropProtectionCache[cacheId] + end + + if g_checkPropProtectionCacheEmpty then + g_checkPropProtectionCacheExpire = now + 3 + g_checkPropProtectionCacheEmpty = false + end + + g_checkPropProtectionCache[cacheId] = false + + -- Support for prop protections + if ent.CPPICanUse then + local status, use = StreamRadioLib.CatchAndErrorNoHaltWithStack(ent.CPPICanUse, ent, ply) + + if not status then + return false + end + + if not use then + return false + end + end + + if SERVER then + local status, use = StreamRadioLib.CatchAndErrorNoHaltWithStack(hook.Run, "PlayerUse", ply, ent) + + if not status then + return false + end + + if not use then + return false + end + end + + g_checkPropProtectionCache[cacheId] = true + return true +end + function StreamRadioLib.CanUseRadio(ply, radio, userEntity) if not IsValid( ply ) then return false end if not IsValid( radio ) then return false end @@ -1080,8 +1156,11 @@ function StreamRadioLib.DeleteFolder(path) end StreamRadioLib.SpawnedRadios = {} + local LastThink = RealTime() +local g_radioCount = 0 + hook.Add("Think", "Streamradio_Entity_Think", function() if not StreamRadioLib then return end if not StreamRadioLib.Loaded then return end @@ -1091,6 +1170,7 @@ hook.Add("Think", "Streamradio_Entity_Think", function() LastThink = now StreamRadioLib.SpawnedRadios = StreamRadioLib.SpawnedRadios or {} + local radioCount = 0 for ent, _ in pairs(StreamRadioLib.SpawnedRadios) do if not IsValid(ent) then @@ -1103,6 +1183,8 @@ hook.Add("Think", "Streamradio_Entity_Think", function() continue end + radioCount = radioCount + 1 + if ent.FastThink then ent:FastThink() end @@ -1112,4 +1194,18 @@ hook.Add("Think", "Streamradio_Entity_Think", function() ent:DormantThink() end + + g_radioCount = radioCount + + if g_radioCount <= 0 then + ClearCheckPropProtectionCache() + end end) + +function StreamRadioLib.GetRadioCount() + return g_radioCount +end + +function StreamRadioLib.HasSpawnedRadios() + return g_radioCount > 0 +end diff --git a/lua/streamradio_core/net.lua b/lua/streamradio_core/net.lua index 82fd6b8..1840ec3 100644 --- a/lua/streamradio_core/net.lua +++ b/lua/streamradio_core/net.lua @@ -82,7 +82,7 @@ function LIB.SendIdentifier(identifier) identifierId = LIBNetwork.NetworkStringToID(identifier) if identifierId == 0 then - ErrorNoHaltWithStack("Identifier '" .. identifier .. "' was not added via util.AddNetworkString() yet.") + StreamRadioLib.ErrorNoHaltWithStack("Identifier '" .. identifier .. "' was not added via util.AddNetworkString() yet.") end end diff --git a/lua/streamradio_core/network.lua b/lua/streamradio_core/network.lua index daceba4..666341b 100644 --- a/lua/streamradio_core/network.lua +++ b/lua/streamradio_core/network.lua @@ -301,7 +301,7 @@ local function pullNWVars(ent) local newvalue = LIB.GetNWVar(ent, data.datatype, name) if oldvalue == newvalue then return end - StreamRadioLib.CatchAndErrorNoHalt(data.callback, ent, name, oldvalue, newvalue) + StreamRadioLib.CatchAndErrorNoHaltWithStack(data.callback, ent, name, oldvalue, newvalue) NW.Names[name].oldvalue = newvalue end @@ -326,7 +326,7 @@ local function pullDTVars(ent) local newvalue = LIB.GetDTNetworkVar(ent, name) if oldvalue == newvalue then return end - StreamRadioLib.CatchAndErrorNoHalt(data.callback, ent, name, oldvalue, newvalue) + StreamRadioLib.CatchAndErrorNoHaltWithStack(data.callback, ent, name, oldvalue, newvalue) NW.Names[name].oldvalue = newvalue end diff --git a/lua/streamradio_core/vr.lua b/lua/streamradio_core/vr.lua index b70fd77..fa452f3 100644 --- a/lua/streamradio_core/vr.lua +++ b/lua/streamradio_core/vr.lua @@ -358,7 +358,7 @@ function LIB.RenderMenu(panel) vrmod.MenuRenderStart(uid) - StreamRadioLib.CatchAndErrorNoHalt(function() + StreamRadioLib.CatchAndErrorNoHaltWithStack(function() mainPanel:PaintManual() end) diff --git a/lua/streamradio_core/wire.lua b/lua/streamradio_core/wire.lua index 799ca4f..864fcb0 100644 --- a/lua/streamradio_core/wire.lua +++ b/lua/streamradio_core/wire.lua @@ -191,7 +191,7 @@ function LIB.WireUserTrace(ent) -- prevent the cache from overflowing if g_WireUserTraceCacheCount > 1024 then - g_WireUserTraceCache = {} + table.Empty(g_WireUserTraceCache) g_WireUserTraceCacheCount = 0 end diff --git a/materials/3dstreamradio/_data/version.vmt b/materials/3dstreamradio/_data/version.vmt index 820b4b3..b4b6cdf 100644 --- a/materials/3dstreamradio/_data/version.vmt +++ b/materials/3dstreamradio/_data/version.vmt @@ -1,2 +1,2 @@ -419 -1686191666 +420 +1686269690