---@class SceneObject ---@field InUseTable table ---@field UnusedTable table ---@field AllTable table ---@field RefreshTime float ---@field IsLimit bool ---@field TotalCount int32 ---@field InSpawnCount int32 ---@field new fun(InTable:SceneObjItem):SceneObject ---@field LoadSceneItem fun(InClass:UClass) ---@field InitSceneItems fun() ---@field OnUseSceneItem fun(InItem:BP_CustomItemBase_C, InPawn:UGCPlayerPawn_C) ---@field SetOneItemToUse fun(IsInit:bool) ---@field SetOneItemToUnused fun() ---@field ChangeItemCount fun(InCount:int32) ---@field GetTotalCount fun():int32 ---@field GetAllItemTable fun():table ---@field GetSetIds fun():table ---@field GetUnusedCount fun():int32 ---@field GetInUseCount fun():int32 ---@field GetAllItemCount fun():int32 ---@field GetNearItem fun(InPawn:UGCPlayerPawn_C):BP_CustomItemBase_C local SceneObject = {}; --- 加载地图上的所有 Buff ---@class SceneObjectItem ---@field Item BP_CustomItemBase_C ---@field IsSet bool 是否设置了Buff ---@field LastTime float 最后一次设置 Buff 的时间 ---@field DisToCenter float 距离中心点的长度 ---@type table 正在使用的表 SceneObject.InUseTable = {}; ---@type table 未使用的表 SceneObject.UnusedTable = {}; ---@type table 所有物品表 SceneObject.AllTable = {}; SceneObject.RefreshTime = 0; SceneObject.IsLimit = false; SceneObject.TotalCount = 0; SceneObject.EventType = nil; --- 已经使用但是还未生成的数量 SceneObject.InSpawnCount = 0; ---@param InTable SceneObjItem function SceneObject:new(InTable) return setmetatable({ RefreshTime = InTable.RefreshTime, IsLimit = InTable.IsLimit, TotalCount = InTable.TotalCount, EventType = InTable.EventType, InUseTable = {}, UnusedTable = {}, AllTable = {}, InSpawnCount = 0, }, { __metatable = self, __index = self, }); end ---@param InClass UClass ---@param InTable table function SceneObject:LoadSceneItem(InClass, InTable) local CenterLoc = GameState:GetCenterPointLocation(); if table.isEmpty(InTable) then local AllActors = {}; UE.FindActorsByClass(InClass, AllActors, function(InIndex, InActor) self:AddOneItemToTableInternal(InActor, CenterLoc); return true; end); else for i, v in pairs(InTable) do if UE.IsA(v, InClass) then self:AddOneItemToTableInternal(v, CenterLoc); end end end UGCLogSystem.LogTree(string.format("[SceneObject:LoadSceneItem] self.AllTable ="), self.AllTable) if self.IsLimit then self:InitSceneItems(); end --- 进行绑定 UGCEventSystem.AddListener(self.EventType, self.OnUseSceneItem, self) end ---@private ---@param v AActor ---@param CenterLoc FVector function SceneObject:AddOneItemToTableInternal(v, CenterLoc) local Name = UE.GetName(v) self.AllTable[Name] = { Item = v, IsSet = false, LastTime = -1, DisToCenter = VectorHelper.GetDistance2D(CenterLoc, v:K2_GetActorLocation()); }; table.insert(self.UnusedTable, Name); end function SceneObject:InitSceneItems() if IsServer then local AllItemCount = self:GetAllItemCount(); self.TotalCount = math.ceil(AllItemCount * self.TotalCount / (self.TotalCount <= 1 and 1 or 100)) if self.TotalCount > AllItemCount then self.TotalCount = AllItemCount; end UGCLogSystem.Log("[SceneObject:InitSceneItems] self.TotalCount = %s", tostring(self.TotalCount)) for i = 1, self.TotalCount do self:SetOneItemToUse(true); end UGCLogSystem.LogTree(string.format("[SceneObject:InitSceneItems] self.InUseTable ="), self.InUseTable) end end function SceneObject:OnUseSceneItem(InItem, InPawn) if IsServer then UGCLogSystem.Log("[SceneObject:OnUseSceneItem] InItem = %s", UE.GetName(InItem)) if not self.IsLimit then return end local Name = UE.GetName(InItem); table.removeValue(self.InUseTable, Name); self.AllTable[Name].IsSet = false; table.insert(self.UnusedTable, Name); UGCEventSystem.SetTimer(GameState, function() self:SetOneItemToUse(false) end, self.RefreshTime); end end function SceneObject:SetOneItemToUse(IsInit) if IsServer then if self:GetUnusedCount() == 0 then return; end table.Shuffle(self.UnusedTable); local ItemName = self.UnusedTable[1]; table.remove(self.UnusedTable, 1) local SceneItem = self.AllTable[ItemName]; UGCLogSystem.Log("[SceneObject:SetOneItemToUse] ItemName = %s", ItemName); SceneItem.Item:PreRandomNewItem(); SceneItem.Item:RandomNewItem(); SceneItem.IsSet = true; SceneItem.LastTime = UE.GetCurrentTime(); table.insert(self.InUseTable, ItemName) SceneItem.Item:OnPostRandomNewItem(); if not IsInit then self.InSpawnCount = self.InSpawnCount - 1; end end end ---@param InCount int32 function SceneObject:ChangeItemCount(InCount) if IsServer then local CurrCount = self:GetInUseCount(); local TotalCount = self.InSpawnCount + CurrCount; if TotalCount < InCount then for i = 1, InCount - TotalCount do self:SetOneItemToUse(true) end elseif TotalCount > InCount then for i = 1, TotalCount - InCount do self:SetOneItemToUnused(); end end self.TotalCount = InCount; end end ---@param InNew float function SceneObject:ChangeItemPercent(InNew) self:ChangeItemCount(InNew * self:GetAllItemCount()); end --- 拿出一个来使用 function SceneObject:SetOneItemToUnused() if IsServer then table.Shuffle(self.InUseTable) local Name = self.InUseTable[1]; table.remove(self.InUseTable, 1); self.AllTable[Name].IsSet = true; self.AllTable[Name].Item:ResetItem(); table.insert(self.UnusedTable, Name) end end ---@param InPawn UGCPlayerPawn_C function SceneObject:GetNearItem(InPawn) local TargetDis, Actor = 1000000, nil; for i, v in pairs(self.InUseTable) do local Dis = VectorHelper.GetActorDis2D(InPawn, self.AllTable[v].Item) if TargetDis > Dis then TargetDis = Dis; Actor = self.AllTable[v].Item; end end return Actor; end ---@param InTable table ---@return table function SceneObject:GetSetIds(InTable) if InTable == nil then InTable = {}; end for i, v in pairs(self.InUseTable) do table.insert(InTable, self.AllTable[v].Item:GetItemId()); end return InTable; end ---@return int32 function SceneObject:GetTotalCount() return self.TotalCount; end ---@return table function SceneObject:GetAllItemTable() return self.AllTable; end ---@return int32 function SceneObject:GetUnusedCount() return table.getCount(self.UnusedTable); end ---@return int32 function SceneObject:GetInUseCount() return table.getCount(self.InUseTable); end ---@return int32 function SceneObject:GetAllItemCount() return table.getCount(self.AllTable); end return SceneObject;