diff --git a/lua/autorun/photon/cl_emv_init.lua b/lua/autorun/photon/cl_emv_init.lua index 247e191c..e6bfd958 100644 --- a/lua/autorun/photon/cl_emv_init.lua +++ b/lua/autorun/photon/cl_emv_init.lua @@ -39,11 +39,9 @@ local function DrawEMVLights() if not should_render:GetBool() then return end for k, v in pairs(EMVU:AllVehicles()) do - if IsValid(v) and v.IsEMV and v:IsEMV() then + if IsValid(v) then if v.Photon_RenderEL then v:Photon_RenderEL() - else - EMVU:MakeEMV(v, v:EMVName()) end if v.Photon_RenderIllum then v:Photon_RenderIllum() diff --git a/lua/autorun/photon/cl_emv_meta.lua b/lua/autorun/photon/cl_emv_meta.lua index fa529e7d..81bf8c4f 100644 --- a/lua/autorun/photon/cl_emv_meta.lua +++ b/lua/autorun/photon/cl_emv_meta.lua @@ -31,9 +31,15 @@ end) local printedErrors = {} +hook.Add("Photon.SimpleNet.ValueChanged", "Photon.SetupEMV", function(name, old, new, ent) + if name == "VehicleIndex" then + EMVU:MakeEMV(ent, new) + end +end) + function EMVU:MakeEMV( emv, name ) - if not emv or not emv:IsValid() or not emv:IsVehicle() then return false end + if not emv or not emv:IsValid() or not emv:IsVehicle() or not emv:IsEMV() then return false end if name == "1" then return end diff --git a/lua/autorun/photon/emv/sh_meta.lua b/lua/autorun/photon/emv/sh_meta.lua new file mode 100644 index 00000000..0ca47c6d --- /dev/null +++ b/lua/autorun/photon/emv/sh_meta.lua @@ -0,0 +1,39 @@ +--[[-- Emergency Lighting Vehicle Meta +@copyright Photon Team +@release development +@author Photon Team +@module VEHICLE +@alias ENT +--]]-- + +local ENT = FindMetaTable("Vehicle") + +function ENT:EMVName() + return self:GetPhotonNet_VehicleIndex("") +end + +function ENT:Photon_GetUnitNumber() + return self:GetPhotonNet_UnitNumber("") +end + +function ENT:Photon_GetLiveryID() + return self:GetPhotonNet_LiveryID("") +end + +function ENT:Photon_SelectionString() + return self:GetPhotonNet_SelectionString("") +end + +function ENT:Photon_SelectionTable() + return string.Split(self:Photon_SelectionString(), ".") +end + +function ENT:Photon_GetUtilStringTable() + return { + "", + self:EMVName(), + self:Photon_GetUnitNumber(), + self:Photon_GetLiveryID(), + self:Photon_SelectionString() + } +end diff --git a/lua/autorun/photon/emv/sv_meta.lua b/lua/autorun/photon/emv/sv_meta.lua index 5cf6d876..561f603a 100644 --- a/lua/autorun/photon/emv/sv_meta.lua +++ b/lua/autorun/photon/emv/sv_meta.lua @@ -250,3 +250,40 @@ end function ENT:ELS_HasAuxSiren() return self:ELS_AuxSirenSet() ~= nil and self:ELS_AuxSirenSet() ~= 0 end + +function ENT:Photon_SetLiveryId(val) + return self:SetPhotonNet_LiveryID(val) +end + +function ENT:Photon_SetUnitNumber(val) + val = tostring(val):upper() + if #val > 3 then + val = string.sub(val, 1, 3) + end + if not val:match("%w") then + val = "" + end + if PHOTON_BANNED_UNIT_IDS[val:lower()] then + val = "" + end + + return self:SetPhotonNet_UnitNumber(val) +end + +function ENT:Photon_SetSelection(index, value) + if not istable(EMVU.Selections[self.Name][index]) then + return + end + + local selectionTable = self:Photon_SelectionTable() + selectionTable[index] = value + self:SetPhotonNet_SelectionString(table.concat(selectionTable, ".")) + + local selectionData = EMVU.Selections[self.Name][index].Options[value] + + if istable(selectionData.Bodygroups) then + for _, bgData in ipairs(selectionData.Bodygroups) do + self:SetBodygroup(bgData[1], bgData[2]) + end + end +end diff --git a/lua/autorun/photon/sh_emv_init.lua b/lua/autorun/photon/sh_emv_init.lua index 84f9e0b3..027fd1de 100644 --- a/lua/autorun/photon/sh_emv_init.lua +++ b/lua/autorun/photon/sh_emv_init.lua @@ -65,6 +65,7 @@ include( "library/emv_auto.lua" ) Photon.include("emv/cl_meta.lua") Photon.include("emv/sv_meta.lua") +Photon.include("emv/sh_meta.lua") local emvVehicleTable = {} local emvLastScan = 0 @@ -82,7 +83,7 @@ function EMVU:UpdateVehicles() end for _,ent in pairs( ents.GetAll() ) do - if IsValid( ent ) and ent.IsEMV and ent:IsEMV() then + if IsValid( ent ) and ent:IsVehicle() and ent.IsEMV and ent:IsEMV() then emvVehicleTable[ #emvVehicleTable + 1 ] = ent end end diff --git a/lua/autorun/photon/sh_emv_meta.lua b/lua/autorun/photon/sh_emv_meta.lua index 647bf4dd..5b63aea8 100644 --- a/lua/autorun/photon/sh_emv_meta.lua +++ b/lua/autorun/photon/sh_emv_meta.lua @@ -8,9 +8,9 @@ local istable = istable function ent:IsEMV() if not IsValid( self ) then return false end + if not self:IsVehicle() then return false end if not EMV_INDEX then return false end - local str = self:GetNW2String( "PhotonLE.EMV_INDEX" ) - if string.StartWith( tostring(str), "ö" ) then return true end + if self:EMVName() ~= "" then return true end return false end @@ -26,15 +26,6 @@ function ent:HasPhotonELS() return true end -function ent:EMVName() - if not IsValid( self ) then return "" end - if not EMV_INDEX then return "" end - if self:IsEMV() then - return string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false )[2] - end - return "" -end - function ent:Photon_GetSpeed() if not IsValid( self ) then return 0 end return self:GetVelocity():Length() @@ -45,14 +36,6 @@ function ent:Photon_AdjustedSpeed() return ( self:GetVelocity():Length() * ( 3600 / 63360 ) ) end -function ent:Photon_GetUnitNumber() - return string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false )[3] or "" -end - -function ent:Photon_GetLiveryID() - return string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false )[4] or "" -end - function ent:Photon_GetAutoSkinIndex() local materials = self:GetMaterials() for i=1,#materials do @@ -75,16 +58,9 @@ end ent.LegacySetSkin = ent.LegacySetSkin or ent.SetSkin function ent:SetSkin( index ) self:LegacySetSkin( index ) - hook.Call( "Photon.EntityChangedSkin", GM, self, index ) -end - -function ent:Photon_SelectionString() - return string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false )[5] -end - -function ent:Photon_SelectionTable() - local selectionString = string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false )[5] - return string.Explode( ".", selectionString, false ) + if self:IsVehicle() and self:IsEMV() then + hook.Call( "Photon.EntityChangedSkin", GM, self, index ) + end end function ent:Photon_SelectionOption( index ) @@ -184,10 +160,6 @@ function ent:Photon_ImportSelectionData( inputData ) return resultTable end -function ent:Photon_GetUtilStringTable() - return string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false ) -end - function ent:Photon_SelectionEnabled() return istable( EMVU.Selections[ self:EMVName() ] ) end diff --git a/lua/autorun/photon/shared/sh_simplenet.lua b/lua/autorun/photon/shared/sh_simplenet.lua index c2becd21..5930d54a 100644 --- a/lua/autorun/photon/shared/sh_simplenet.lua +++ b/lua/autorun/photon/shared/sh_simplenet.lua @@ -5,7 +5,6 @@ Easily optimise networking for setting local values on entities. @author Photon Team @module Photon.SNet @alias NET -@todo Add Spawn-Sync for all Photon Variables. --]]-- Photon = Photon or {} @@ -16,6 +15,7 @@ local ENT = FindMetaTable("Entity") if SERVER then util.AddNetworkString("Photon_SimpleNet_Change") util.AddNetworkString("Photon_SimpleNet_RequestSync") + util.AddNetworkString("Photon_SimpleNet_Resync") end NET.BOOL = 1 @@ -83,6 +83,31 @@ function NET:Map(name, netType, extra) end if SERVER then + --- Send the current value of a networked variable to a recipient. + -- @ent ent The entity the value belongs to. + -- @str name The name to send. + -- @param val Value to send. + -- @param[opt] to Player to send to. Broadcasts to everyone if omitted. + -- @internal + -- @state server + function NET:SendChange(ent, name, val, to) + local idx, netType, extra = unpack(self.RMap[name]) + if not idx then + PhotonError(("Attempted to call SimpleNet:Change with an unregistered name: %s"):format(name)) + return + end + + net.Start("Photon_SimpleNet_Change") + net.WriteEntity(ent) + net.WriteUInt(idx, self.Bits) + self.WriteFunctions[netType](val, extra) + if to then + net.Send(to) + else + net.Broadcast() + end + end + --- Change a networked entity variable. -- @ent ent The entity to change the value on. -- @str name The name to change. @@ -96,20 +121,59 @@ if SERVER then local old = ent[varName] if val ~= old then ent[varName] = val + self:SendChange(ent, name, val) + end + end - local idx, netType, extra = unpack(self.RMap[name]) - if not idx then - PhotonError(("Attempted to call SimpleNet:Change with an unregistered name: %s"):format(name)) - return + --- Resend every currently-set networked variable on every vehicle to a + -- player, batched into a single net message. + -- Needed because values are only broadcast when they change, so a player + -- who joins after a value was set would otherwise never receive it. + -- @ply to Player to send the current state to. + -- @internal + -- @state server + function NET:Resync(to) + local groups = {} + for _, ent in ipairs(ents.GetAll()) do + if IsValid(ent) and ent:IsVehicle() then + local fields + for name in pairs(self.RMap) do + local val = ent[self.Normalise(name)] + if val ~= nil then + fields = fields or {} + local idx, netType, extra = unpack(self.RMap[name]) + fields[#fields + 1] = {idx, netType, extra, val} + end + end + if fields then + groups[#groups + 1] = {ent, fields} + end end + end - net.Start("Photon_SimpleNet_Change") + if #groups == 0 then return end + + net.Start("Photon_SimpleNet_Resync") + net.WriteUInt(#groups, 16) + for _, group in ipairs(groups) do + local ent, fields = group[1], group[2] net.WriteEntity(ent) - net.WriteUInt(idx, self.Bits) - self.WriteFunctions[netType](val, extra) - net.Broadcast() + net.WriteUInt(#fields, self.Bits) + for _, field in ipairs(fields) do + local idx, netType, extra, val = field[1], field[2], field[3], field[4] + net.WriteUInt(idx, self.Bits) + self.WriteFunctions[netType](val, extra) + end end + net.Send(to) end + + hook.Add("PlayerInitialSpawn", "Photon.SimpleNet.Resync", function(ply) + timer.Simple(2, function() + if not IsValid(ply) then return end + NET:Resync(ply) + end) + end) end --- Get the latest cached version of a value on an entity. @@ -145,11 +209,33 @@ if SERVER then end if CLIENT then - net.Receive("Photon_SimpleNet_Change", function(len, ply) + net.Receive("Photon_SimpleNet_Change", function() local ent = net.ReadEntity() local idx = net.ReadUInt(NET.Bits) local name, netType, extra = unpack(NET.FMap[idx]) - ent[NET.Normalise(name)] = NET.ReadFunctions[netType](extra) + local normalName = NET.Normalise(name) + local old = ent[normalName] + ent[normalName] = NET.ReadFunctions[netType](extra) + hook.Run("Photon.SimpleNet.ValueChanged", name, old, ent[normalName], ent) + end) + + net.Receive("Photon_SimpleNet_Resync", function() + local entCount = net.ReadUInt(16) + for _ = 1, entCount do + local ent = net.ReadEntity() + local fieldCount = net.ReadUInt(NET.Bits) + for _ = 1, fieldCount do + local idx = net.ReadUInt(NET.Bits) + local name, netType, extra = unpack(NET.FMap[idx]) + local val = NET.ReadFunctions[netType](extra) + if IsValid(ent) then + local normalName = NET.Normalise(name) + local old = ent[normalName] + ent[normalName] = val + hook.Run("Photon.SimpleNet.ValueChanged", name, old, val, ent) + end + end + end end) hook.Add("NotifyShouldTransmit", "EMVU.Net.NotifyShouldTransmit", function(ent, shouldTransmit) @@ -161,7 +247,7 @@ if CLIENT then end) end -local UInt, Bool = NET.UINT, NET.BOOL +local UInt, Bool, Str = NET.UINT, NET.BOOL, NET.STR NET:Map("CurrentSignal", UInt, 2) NET:Map("Blinker", UInt, 2) @@ -184,3 +270,8 @@ NET:Map("TrafficOption", UInt, 4) NET:Map("IlluminationOn", Bool) NET:Map("IlluminationOption", UInt, 4) NET:Map("Preset", UInt, 10) + +NET:Map("VehicleIndex", Str) +NET:Map("UnitNumber", Str) +NET:Map("LiveryID", Str) +NET:Map("SelectionString", Str) diff --git a/lua/autorun/photon/sv_emv_meta.lua b/lua/autorun/photon/sv_emv_meta.lua index 13b26c2c..e1672adf 100644 --- a/lua/autorun/photon/sv_emv_meta.lua +++ b/lua/autorun/photon/sv_emv_meta.lua @@ -555,23 +555,6 @@ function EMVU:MakeEMV( ent, emv ) end end - function ent:Photon_SetLiveryId( val ) - local curdata = string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false ) - curdata[4] = val - self:SetNW2String( "PhotonLE.EMV_INDEX", table.concat( curdata, "ö" )) - end - - function ent:Photon_SetUnitNumber( val ) - val = string.upper( tostring( val ) ) - if string.len( val ) > 3 then val = string.sub( val, 1, 3 ) end - if not string.match( val, "%w" ) then val = "" end - if PHOTON_BANNED_UNIT_IDS[ string.lower( val ) ] then val = "" end - local curdata = string.Explode( "ö", self:GetNW2String( "PhotonLE.EMV_INDEX" ), false ) - curdata[3] = val - self:SetNW2String( "PhotonLE.EMV_INDEX", table.concat( curdata, "ö" ) ) - return val - end - function ent:Photon_ApplySubMaterials() if istable( EMVU.SubMaterials[ self.Name ] ) then local submaterials = EMVU.SubMaterials[ self.Name ] @@ -583,25 +566,6 @@ function EMVU:MakeEMV( ent, emv ) end end - function ent:Photon_SetSelection( index, value ) - -- print(string.format( "index: %s value: %s", index, value )) - if istable( EMVU.Selections[ self.Name ][ index ] ) then - local selectionTable = self:Photon_SelectionTable() - selectionTable[index] = value - -- PrintTable( selectionTable ) - local photonUtilString = self:Photon_GetUtilStringTable() - photonUtilString[5] = table.concat( selectionTable, "." ) - --PrintTable( photonUtilString ) - self:Photon_SetUtilString( table.concat( photonUtilString, "ö" ) ) - local selectionData = EMVU.Selections[ self.Name ][ index ].Options[value] - if istable( selectionData.Bodygroups ) then - for _,bgData in pairs( selectionData.Bodygroups ) do - self:SetBodygroup( bgData[1], bgData[2] ) - end - end - end - end - function ent:Photon_ResetSelections() if istable( EMVU.Selections[ self.Name ] ) then for i=1,#EMVU.Selections[ self.Name ] do @@ -610,10 +574,6 @@ function EMVU:MakeEMV( ent, emv ) end end - function ent:Photon_SetUtilString( str ) - self:SetNW2String( "PhotonLE.EMV_INDEX", str ) - end - function ent:Photon_HasManualWind() local set = self:ELS_SirenSet() return istable( EMVU.GetSirenTable()[set].Gain ) @@ -638,7 +598,7 @@ function EMVU:MakeEMV( ent, emv ) end ent.IsEMV = true - ent:SetNW2String( "PhotonLE.EMV_INDEX", "ö" .. tostring( ent.Name ) .. "ööö." ) -- Al + ent:SetPhotonNet_VehicleIndex(ent.Name) ------ APPLY EMV PARAMETERS ------