diff --git a/lua/pac3/core/client/hooks.lua b/lua/pac3/core/client/hooks.lua index 49cb5e2ab..53e361ad0 100644 --- a/lua/pac3/core/client/hooks.lua +++ b/lua/pac3/core/client/hooks.lua @@ -57,13 +57,13 @@ do if ply.pac_global_animation_rate == 0 then animrate = ply:GetModelScale() * 2 elseif ply.pac_global_animation_rate ~= 1 then - ply:SetCycle((pac.RealTime * ply.pac_global_animation_rate)%1) + ply:SetCycle((pac.RealTime * ply.pac_global_animation_rate) % 1) animrate = ply.pac_global_animation_rate end end if ply.pac_animation_sequences then - local part, thing = next(ply.pac_animation_sequences) + local part = next(ply.pac_animation_sequences) if part and part:IsValid() then @@ -195,8 +195,3 @@ pac.AddHook("pac_PlayerFootstep", "events", function(ply, pos, snd, vol) return true end end) - -net.Receive("pac_effect_precached", function() - local name = net.ReadString() - pac.CallHook("EffectPrecached", name) -end) diff --git a/lua/pac3/core/client/init.lua b/lua/pac3/core/client/init.lua index ba7104752..21aaa0264 100644 --- a/lua/pac3/core/client/init.lua +++ b/lua/pac3/core/client/init.lua @@ -48,6 +48,7 @@ pac.animations = include("pac3/libraries/animations.lua") include("pac3/core/shared/init.lua") +pac.pcfprovider = include("pac3/libraries/pcfprovider.lua") pac.urltex = include("pac3/libraries/urltex.lua") include("parts.lua") diff --git a/lua/pac3/core/client/parts/effect.lua b/lua/pac3/core/client/parts/effect.lua index 6e50bd192..b5adb2a44 100644 --- a/lua/pac3/core/client/parts/effect.lua +++ b/lua/pac3/core/client/parts/effect.lua @@ -4,11 +4,11 @@ local ParticleEffect = ParticleEffect local BUILDER, PART = pac.PartTemplate("base_drawable") PART.ClassName = "effect" -PART.Groups = {'effects', 'model', 'entity'} -PART.Icon = 'icon16/wand.png' +PART.Groups = {"effects", "model", "entity"} +PART.Icon = "icon16/wand.png" BUILDER:StartStorableVars() - BUILDER:GetSet("Effect", "default", {enums = function() return pac.particle_list end}) + BUILDER:GetSet("Effect", "default", {enums = function() return pac.pcfprovider.GetParticleList() end}) BUILDER:GetSet("Loop", true) BUILDER:GetSet("Follow", true) BUILDER:GetSet("Rate", 1, {editor_sensitivity = 0.1}) @@ -24,7 +24,7 @@ BUILDER:EndStorableVars() BUILDER:RemoveProperty("Translucent") PART.Translucent = false -- otherwise OnDraw won't be called -local BaseClass_GetOwner = PART.GetOwner +--local BaseClass_GetOwner = PART.GetOwner function PART:GetNiceName() return pac.PrettifyName(self:GetEffect()) @@ -32,89 +32,18 @@ end function PART:Initialize() self:SetEffect(self.Effect) - - if not pac.particle_list then - local found = {} - - for file_name in pairs(pac_loaded_particle_effects) do - local ok, err = pcall(function() - local data = file.Read("particles/"..file_name, "GAME", "b") - if data then - for str in data:gmatch("\3%c([%a_]+)%c") do - if #str > 1 then - found[str] = str - end - end - end - end) - - if not ok then - local msg = "unable to parse particle file " .. file_name .. ": " .. err - self:SetError(msg) - pac.Message(Color(255, 50, 50), msg) - end - end - - pac.particle_list = found - end end PART.last_spew = 0 -if not pac_loaded_particle_effects then - pac_loaded_particle_effects = {} - - for _, file_name in pairs(file.Find("particles/*.pcf", "GAME")) do - if not pac_loaded_particle_effects[file_name] and not pac.BlacklistedParticleSystems[file_name:lower()] then - game.AddParticles("particles/" .. file_name) - end - - pac_loaded_particle_effects[file_name] = true - end -end - -local already = {} -local alreadyServer = {} -local function pac_request_precache(name) - if already[name] then return end - already[name] = true - PrecacheParticleSystem(name) - net.Start("pac_request_precache") - net.WriteString(name) - net.SendToServer() -end - function PART:SetEffect(name) - self.waitingForServer = true self.Effect = name - self.Ready = alreadyServer[name] or false - - if not alreadyServer[name] then - pac_request_precache(name) - else - self.waitingForServer = false - end -end - -pac.AddHook("pac_EffectPrecached", "pac_Effects", function(name) - if alreadyServer[name] then return end - alreadyServer[name] = true - pac.dprint("effect %q precached!", name) - pac.CallRecursiveOnAllParts("OnEffectPrecached", name) -end) - -function PART:OnEffectPrecached(name) - if self.Effect == name then - self.Ready = true - self.waitingForServer = false - end + self.Ready = false end function PART:OnDraw() if not self.Ready then - if not self.waitingForServer then - self:SetEffect(self.Effect) - end + self.Ready = pac.pcfprovider.LoadEffect(self.Effect) return end @@ -143,7 +72,7 @@ function PART:OnHide() end function PART:OnShow(from_rendering) - if from_rendering then + if from_rendering and self.Ready then self:Emit(self:GetDrawPosition()) end end diff --git a/lua/pac3/core/server/effects.lua b/lua/pac3/core/server/effects.lua deleted file mode 100644 index cff75842a..000000000 --- a/lua/pac3/core/server/effects.lua +++ /dev/null @@ -1,59 +0,0 @@ -pac.EffectsBlackList = -{ - "frozen_steam", - "portal_rift_01", - "explosion_silo", - "citadel_shockwave_06", - "citadel_shockwave", - "choreo_launch_rocket_start", - "choreo_launch_rocket_jet", -} - -if not pac_loaded_particle_effects then - pac_loaded_particle_effects = {} - local files = file.Find("particles/*.pcf", "GAME") - - for key, file_name in pairs(files) do - if not pac_loaded_particle_effects[file_name] and not pac.BlacklistedParticleSystems[file_name:lower()] then - game.AddParticles("particles/" .. file_name) - end - - pac_loaded_particle_effects[file_name] = true - end - - pac.Message('Loaded total ', #files, ' particle systems') -end - -util.AddNetworkString("pac_effect_precached") -util.AddNetworkString("pac_request_precache") - -function pac.PrecacheEffect(name) - PrecacheParticleSystem(name) - net.Start("pac_effect_precached") - net.WriteString(name) - net.Broadcast() -end - -local queue = {} -net.Receive("pac_request_precache", function(len, pl) - local name = net.ReadString() - if table.HasValue(pac.EffectsBlackList, name) then return end - - -- Each player gets a 50 length queue - local plqueue = queue[pl] - if plqueue then - if #plqueue<50 then plqueue[#plqueue+1] = name end - else - plqueue = {name} - queue[pl] = plqueue - local function processQueue() - if #plqueue == 0 then - queue[pl] = nil - else - timer.Simple(0.5, processQueue) - pac.PrecacheEffect(table.remove(plqueue,1)) - end - end - processQueue() - end -end) diff --git a/lua/pac3/core/server/init.lua b/lua/pac3/core/server/init.lua index 28f092079..e807965b2 100644 --- a/lua/pac3/core/server/init.lua +++ b/lua/pac3/core/server/init.lua @@ -22,7 +22,6 @@ include("util.lua") include("pac3/core/shared/init.lua") -include("effects.lua") include("event.lua") include("net_messages.lua") include("test_suite_backdoor.lua") diff --git a/lua/pac3/core/shared/init.lua b/lua/pac3/core/shared/init.lua index 382905062..875ab28ec 100644 --- a/lua/pac3/core/shared/init.lua +++ b/lua/pac3/core/shared/init.lua @@ -7,54 +7,55 @@ include("entity_mutator.lua") include("hash.lua") pac.StringStream = include("pac3/libraries/string_stream.lua") +pac.pcfparser = include("pac3/libraries/pcfparser.lua") CreateConVar("pac_sv_draw_distance", 0, CLIENT and FCVAR_REPLICATED or bit.bor(FCVAR_REPLICATED, FCVAR_ARCHIVE)) do local tohash = { -- Crash - 'eye_muzzle.pcf', -- E.Y.E: Divine Cybermancy effect that crashes gmod. https://github.com/CapsAdmin/pac3/issues/1410 - 'weapon_unusual_isotope.pcf', + "eye_muzzle.pcf", -- E.Y.E: Divine Cybermancy effect that crashes gmod. https://github.com/CapsAdmin/pac3/issues/1410 + "weapon_unusual_isotope.pcf", -- Invalid - 'blood_fx.pcf', - 'boomer_fx.pcf', - 'charger_fx.pcf', - 'default.pcf', - 'electrical_fx.pcf', - 'environmental_fx.pcf', - 'fire_01l4d.pcf', - 'fire_fx.pcf', - 'fire_infected_fx.pcf', - 'firework_crate_fx.pcf', - 'fireworks_fx.pcf', - 'footstep_fx.pcf', - 'gen_dest_fx.pcf', - 'hunter_fx.pcf', - 'infected_fx.pcf', - 'insect_fx.pcf', - 'item_fx.pcf', - 'locator_fx.pcf', - 'military_artillery_impacts.pcf', - 'rain_fx.pcf', - 'rain_storm_fx.pcf', - 'rope_fx.pcf', - 'screen_fx.pcf', - 'smoker_fx.pcf', - 'speechbubbles.pcf', - 'spitter_fx.pcf', - 'steam_fx.pcf', - 'steamworks.pcf', - 'survivor_fx.pcf', - 'tank_fx.pcf', - 'tanker_explosion.pcf', - 'test_collision.pcf', - 'test_distancealpha.pcf', - 'ui_fx.pcf', - 'vehicle_fx.pcf', - 'water_fx.pcf', - 'weapon_fx.pcf', - 'witch_fx.pcf' + "blood_fx.pcf", + "boomer_fx.pcf", + "charger_fx.pcf", + "default.pcf", + "electrical_fx.pcf", + "environmental_fx.pcf", + "fire_01l4d.pcf", + "fire_fx.pcf", + "fire_infected_fx.pcf", + "firework_crate_fx.pcf", + "fireworks_fx.pcf", + "footstep_fx.pcf", + "gen_dest_fx.pcf", + "hunter_fx.pcf", + "infected_fx.pcf", + "insect_fx.pcf", + "item_fx.pcf", + "locator_fx.pcf", + "military_artillery_impacts.pcf", + "rain_fx.pcf", + "rain_storm_fx.pcf", + "rope_fx.pcf", + "screen_fx.pcf", + "smoker_fx.pcf", + "speechbubbles.pcf", + "spitter_fx.pcf", + "steam_fx.pcf", + "steamworks.pcf", + "survivor_fx.pcf", + "tank_fx.pcf", + "tanker_explosion.pcf", + "test_collision.pcf", + "test_distancealpha.pcf", + "ui_fx.pcf", + "vehicle_fx.pcf", + "water_fx.pcf", + "weapon_fx.pcf", + "witch_fx.pcf" } pac.BlacklistedParticleSystems = {} @@ -63,3 +64,14 @@ do pac.BlacklistedParticleSystems[val] = true end end + +pac.EffectsBlackList = +{ + frozen_steam = true, + portal_rift_01 = true, + explosion_silo = true, + citadel_shockwave_06 = true, + citadel_shockwave = true, + choreo_launch_rocket_start = true, + choreo_launch_rocket_jet = true, +} diff --git a/lua/pac3/extra/client/init.lua b/lua/pac3/extra/client/init.lua index e882db6e9..f6fb40085 100644 --- a/lua/pac3/extra/client/init.lua +++ b/lua/pac3/extra/client/init.lua @@ -3,5 +3,6 @@ pacx = pacx or {} include("pac3/extra/shared/init.lua") include("contraption.lua") +include("map_outfit.lua") include("pac2_compat.lua") include("wire_expression_extension.lua") \ No newline at end of file diff --git a/lua/pac3/extra/client/map_outfit.lua b/lua/pac3/extra/client/map_outfit.lua new file mode 100644 index 000000000..60848a7ed --- /dev/null +++ b/lua/pac3/extra/client/map_outfit.lua @@ -0,0 +1,22 @@ +local WAIT_INTERVAL = 0.1 +local WAIT_ATTEMPTS = 300 + +local pending = 0 + +net.Receive("pac_map_outfit_effect", function() + local index = net.ReadUInt(16) + local effect = net.ReadString() + + pending = pending + 1 + local timer_name = "pac_map_outfit_effect_" .. pending + + timer.Create(timer_name, WAIT_INTERVAL, WAIT_ATTEMPTS, function() + local ent = Entity(index) + if not ent:IsValid() then return end + if not pac.pcfprovider.LoadEffect(effect) then return end + + timer.Remove(timer_name) + + ParticleEffectAttach(effect, PATTACH_ABSORIGIN_FOLLOW, ent, 0) + end) +end) diff --git a/lua/pac3/extra/server/map_outfit.lua b/lua/pac3/extra/server/map_outfit.lua index 9773f4532..8e6a1c4cf 100644 --- a/lua/pac3/extra/server/map_outfit.lua +++ b/lua/pac3/extra/server/map_outfit.lua @@ -1,21 +1,12 @@ pacx.SpawnedMapEntities = pacx.SpawnedMapEntities or {} +util.AddNetworkString("pac_map_outfit_effect") + local VEC0 = Vector(0, 0, 0) local ANG0 = Angle(0, 0, 0) -local VEC1 = Vector(1, 1, 1) local function tocolor(v, a) return Color(v.x, v.y, v.z, a) end -local function has_clip(part) - for key, part in pairs(part.children) do - if part.self.ClassName == "clip" then - return true - end - end - - return false -end - local function set_pos(ent, data, parent) local ppos = Vector() local pang = Angle() @@ -25,7 +16,7 @@ local function set_pos(ent, data, parent) pang = parent:GetAngles() end - local pos, ang = LocalToWorld((data.Position or VEC0)+ (data.PositionOffset or VEC0), (data.Angles or ANG0) + (data.AngleOffset or ANG0), ppos, pang) + local pos, ang = LocalToWorld((data.Position or VEC0) + (data.PositionOffset or VEC0), (data.Angles or ANG0) + (data.AngleOffset or ANG0), ppos, pang) ent:SetPos(pos) ent:SetAngles(ang) @@ -93,8 +84,13 @@ local spawn_handlers = { end, effect = function(part, parent) - if parent:IsValid() and part.data.Effect then - ParticleEffectAttach(part.data.Effect, PATTACH_ABSORIGIN_FOLLOW, parent, 0) + local effect = part.self.Effect + + if parent:IsValid() and effect and effect ~= "" then + net.Start("pac_map_outfit_effect") + net.WriteUInt(parent:EntIndex(), 16) + net.WriteString(effect) + net.Broadcast() end end, } @@ -137,7 +133,7 @@ concommand.Add("pac_spawn_map", function(ply, _, args) return ply:PrintMessage(HUD_PRINTCONSOLE, "Please enter a pac name") end - for _,v in pairs(pacx.SpawnedMapEntities) do + for _, v in pairs(pacx.SpawnedMapEntities) do SafeRemoveEntity(v) end diff --git a/lua/pac3/libraries/pcfparser.lua b/lua/pac3/libraries/pcfparser.lua new file mode 100644 index 000000000..f2037fe3c --- /dev/null +++ b/lua/pac3/libraries/pcfparser.lua @@ -0,0 +1,119 @@ +local pcfparser = {} + +local string_find = string.find +local string_sub = string.sub +local string_match = string.match +local string_lower = string.lower +local file_Open = file.Open + +local DEFINITION_TYPE = "DmeParticleSystemDefinition" +local HEADER_PREFIX = "