From 2c8adf58cbdb2c0ff93158a3babe4dc8206b9abf Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 17 Jul 2023 16:26:53 +0200 Subject: [PATCH 1/2] #CLIENTMENU * Rewrite with a different data approach --- Moose Development/Moose/Core/ClientMenu.lua | 767 +++++++++----------- 1 file changed, 330 insertions(+), 437 deletions(-) diff --git a/Moose Development/Moose/Core/ClientMenu.lua b/Moose Development/Moose/Core/ClientMenu.lua index 60a74fe11..d58c62f4b 100644 --- a/Moose Development/Moose/Core/ClientMenu.lua +++ b/Moose Development/Moose/Core/ClientMenu.lua @@ -3,12 +3,14 @@ -- **Main Features:** -- -- * For complex, non-static menu structures --- * Separation of menu tree creation from pushing it to clients +-- * Lightweigt implementation as alternative to MENU +-- * Separation of menu tree creation from menu on the clients's side -- * Works with a SET_CLIENT set of clients -- * Allow manipulation of the shadow tree in various ways -- * Push to all or only one client --- * Change entries' menu text, even if they have a sub-structure --- * Option to make an entry usable once +-- * Change entries' menu text +-- * Option to make an entry usable once only across all clients +-- * Auto appends GROUP and CLIENT objects to menu calls -- -- === -- @@ -37,9 +39,10 @@ -- @field #table parentpath -- @field #CLIENTMENU Parent -- @field Wrapper.Client#CLIENT client --- @field #number GID --- @field #number ID +-- @field #number GroupID Group ID +-- @field #number ID Entry ID -- @field Wrapper.Group#GROUP group +-- @field #string UUID Unique ID based on path+name -- @field #string Function -- @field #table Functionargs -- @field #table Children @@ -54,12 +57,12 @@ CLIENTMENU = { ClassName = "CLIENTMENUE", lid = "", - version = "0.0.1", + version = "0.1.0", name = nil, path = nil, group = nil, client = nil, - GID = nil, + GroupID = nil, Children = {}, Once = false, Generic = false, @@ -87,20 +90,26 @@ function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...) if Client then self.group = Client:GetGroup() self.client = Client - self.GID = self.group:GetID() + self.GroupID = self.group:GetID() else self.Generic = true end self.name = Text or "unknown entry" if Parent then - self.parentpath = Parent:GetPath() - Parent:AddChild(self) + if Parent:IsInstanceOf("MENU_BASE") then + self.parentpath = Parent.MenuPath + else + self.parentpath = Parent:GetPath() + Parent:AddChild(self) + end end self.Parent = Parent self.Function = Function - self.Functionargs = arg + self.Functionargs = arg or {} + table.insert(self.Functionargs,self.group) + table.insert(self.Functionargs,self.client) if self.Functionargs and self.debug then - self:I({"Functionargs",self.Functionargs}) + self:T({"Functionargs",self.Functionargs}) end if not self.Generic then if Function ~= nil then @@ -120,9 +129,9 @@ function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...) self:Clear() end end - self.path = missionCommands.addCommandForGroup(self.GID,Text,self.parentpath, self.CallHandler) + self.path = missionCommands.addCommandForGroup(self.GroupID,Text,self.parentpath, self.CallHandler) else - self.path = missionCommands.addSubMenuForGroup(self.GID,Text,self.parentpath) + self.path = missionCommands.addSubMenuForGroup(self.GroupID,Text,self.parentpath) end else if self.parentpath then @@ -131,8 +140,9 @@ function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...) self.path = {} end self.path[#self.path+1] = Text - self:T({self.path}) end + self.UUID = table.concat(self.path,";") + self:T({self.UUID}) self.Once = false -- Log id. self.lid=string.format("CLIENTMENU %s | %s | ", self.ID, self.name) @@ -140,6 +150,21 @@ function CLIENTMENU:NewEntry(Client,Text,Parent,Function,...) return self end +--- Create a UUID +-- @param #CLIENTMENU self +-- @param #CLIENTMENU Parent The parent object if any +-- @param #string Text The menu entry text +-- @return #string UUID +function CLIENTMENU:CreateUUID(Parent,Text) + local path = {} + if Parent and Parent.path then + path = Parent.path + end + path[#path+1] = Text + local UUID = table.concat(path,";") + return UUID +end + --- Set the CLIENTMENUMANAGER for this entry. -- @param #CLIENTMENU self -- @param #CLIENTMENUMANAGER Controller The controlling object. @@ -163,8 +188,9 @@ end -- @return #CLIENTMENU self function CLIENTMENU:RemoveF10() self:T(self.lid.."RemoveF10") - if not self.Generic then - missionCommands.removeItemForGroup(self.GID , self.path ) + if self.GroupID then + --self:I(self.lid.."Removing "..table.concat(self.path,";")) + missionCommands.removeItemForGroup(self.GroupID , self.path ) end return self end @@ -177,6 +203,14 @@ function CLIENTMENU:GetPath() return self.path end +--- Get the UUID. +-- @param #CLIENTMENU self +-- @return #string UUID +function CLIENTMENU:GetUUID() + self:T(self.lid.."GetUUID") + return self.UUID +end + --- Link a child entry. -- @param #CLIENTMENU self -- @param #CLIENTMENU Child The entry to link as a child. @@ -202,7 +236,7 @@ end -- @return #CLIENTMENU self function CLIENTMENU:RemoveSubEntries() self:T(self.lid.."RemoveSubEntries") - --self:T({self.Children}) + self:T({self.Children}) for _id,_entry in pairs(self.Children) do self:T("Removing ".._id) if _entry then @@ -211,10 +245,10 @@ function CLIENTMENU:RemoveSubEntries() if _entry.Parent then _entry.Parent:RemoveChild(self) end - if self.Controller then - self.Controller:_RemoveByID(_entry.ID) - end - _entry = nil + --if self.Controller then + --self.Controller:_RemoveByID(_entry.ID) + --end + --_entry = nil end end return self @@ -235,9 +269,9 @@ function CLIENTMENU:Clear() if self.Parent then self.Parent:RemoveChild(self) end - if self.Controller then - self.Controller:_RemoveByID(self.ID) - end + --if self.Controller then + --self.Controller:_RemoveByID(self.ID) + --end return self end @@ -256,9 +290,9 @@ end -- @field #string version Version string -- @field #string name Name -- @field Core.Set#SET_CLIENT clientset The set of clients this menu manager is for --- @field #table structure --- @field #table replacementstructure +-- @field #table flattree -- @field #table rootentries +-- @field #table menutree -- @field #number entrycount -- @field #boolean debug -- @extends Core.Base#BASE @@ -310,27 +344,28 @@ end -- -- ## Remove a single entry and also it's subtree -- --- menumgr:Clear(mymenu_lv3a) +-- menumgr:DeleteEntry(mymenu_lv3a) -- -- ## Add a single entry -- -- local baimenu = menumgr:NewEntry("BAI",mymenu_lv1b) --- menumgr:AddEntry(baimenu) +-- +-- menumgr:AddEntry(baimenu) +-- +-- ## Add an entry with a function +-- +-- local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, Argument1, Argument1) +-- +-- Now, the class will **automatically append the call with GROUP and CLIENT objects**, as this is can only be done when pushing the entry to the clients. So, the actual function implementation needs to look like this: +-- +-- function TestFunction( Argument1, Argument2, Group, Client) +-- +-- **Caveat is**, that you need to ensure your arguments are not **nil** or **false**, as LUA will optimize those away. You would end up having Group and Client in wrong places in the function call. Hence, +-- if you need/ want to send **nil** or **false**, send a place holder instead and ensure your function can handle this, e.g. +-- +-- local baimenu = menumgr:NewEntry("Task Action", mymenu_lv1b, TestFunction, "nil", Argument1) -- --- ## Prepare and push a partial replacement in the tree --- --- menumgr:PrepareNewReplacementStructure() --- local submenu = menumgr:NewReplacementEntry("New Level 2 ba",mymenu_lv2a) --- menumgr:NewReplacementEntry("New Level 2 bb",mymenu_lv2a) --- menumgr:NewReplacementEntry("Deleted",mymenu_lv2a) --- menumgr:NewReplacementEntry("New Level 2 bd",mymenu_lv2a) --- menumgr:NewReplacementEntry("SubLevel 3 baa",submenu) --- menumgr:NewReplacementEntry("SubLevel 3 bab",submenu) --- menumgr:NewReplacementEntry("SubLevel 3 bac",submenu) --- menumgr:NewReplacementEntry("SubLevel 3 bad",submenu) --- menumgr:ReplaceEntries(mymenu_lv2a) --- --- ## Change the text of an entry in the menu tree +-- ## Change the text of a leaf entry in the menu tree -- -- menumgr:ChangeEntryTextForAll(mymenu_lv1b,"Attack") -- @@ -346,31 +381,17 @@ end CLIENTMENUMANAGER = { ClassName = "CLIENTMENUMANAGER", lid = "", - version = "0.0.1", + version = "0.1.0", name = nil, clientset = nil, - --- - -- @field #CLIENTMENUMANAGER.Structure - structure = { - generic = {}, - IDs = {}, - }, - --- - -- #CLIENTMENUMANAGER.ReplacementStructure - replacementstructure = { - generic = {}, - IDs = {}, - }, + menutree = {}, + flattree = {}, + playertree = {}, entrycount = 0, rootentries = {}, debug = true, } ---- --- @type CLIENTMENUMANAGER.Structure --- @field #table generic --- @field #table IDs - --- Create a new ClientManager instance. -- @param #CLIENTMENUMANAGER self -- @param Core.Set#SET_CLIENT ClientSet The set of clients to manage. @@ -384,7 +405,7 @@ function CLIENTMENUMANAGER:New(ClientSet, Alias) -- Log id. self.lid=string.format("CLIENTMENUMANAGER %s | %s | ", self.version, self.name) if self.debug then - self:I(self.lid.."Created") + self:T(self.lid.."Created") end return self end @@ -400,271 +421,177 @@ function CLIENTMENUMANAGER:NewEntry(Text,Parent,Function,...) self:T(self.lid.."NewEntry "..Text or "None") self.entrycount = self.entrycount + 1 local entry = CLIENTMENU:NewEntry(nil,Text,Parent,Function,unpack(arg)) - self.structure.generic[self.entrycount] = entry - self.structure.IDs[entry.ID] = self.entrycount if not Parent then - self.rootentries[self.entrycount] = self.entrycount + self.rootentries[self.entrycount] = entry end + local depth = #entry.path + if not self.menutree[depth] then self.menutree[depth] = {} end + table.insert(self.menutree[depth],entry.UUID) + self.flattree[entry.UUID] = entry return entry end ---- Find **first** matching entry in the generic structure by the menu text. +--- Check matching entry in the generic structure by UUID. -- @param #CLIENTMENUMANAGER self --- @param #string Text Text of the F10 menu entry. +-- @param #string UUID UUID of the menu entry. +-- @return #boolean Exists +function CLIENTMENUMANAGER:EntryUUIDExists(UUID) + local exists = self.flattree[UUID] and true or false + return exists +end + +--- Find matching entry in the generic structure by UUID. +-- @param #CLIENTMENUMANAGER self +-- @param #string UUID UUID of the menu entry. -- @return #CLIENTMENU Entry The #CLIENTMENU object found or nil. --- @return #number GID GID The GID found or nil. -function CLIENTMENUMANAGER:FindEntryByText(Text) - self:T(self.lid.."FindEntryByText "..Text or "None") +function CLIENTMENUMANAGER:FindEntryByUUID(UUID) + self:T(self.lid.."FindEntryByUUID "..UUID or "None") local entry = nil - local gid = nil - for _gid,_entry in UTILS.spairs(self.structure.generic) do + for _gid,_entry in pairs(self.flattree) do local Entry = _entry -- #CLIENTMENU - if Entry and Entry.name == Text then + if Entry and Entry.UUID == UUID then entry = Entry - gid = _gid end end - return entry, gid -end - ---- Find first matching entry in the generic structure by the GID. --- @param #CLIENTMENUMANAGER self --- @param #number GID The GID of the entry to find. --- @return #CLIENTMENU Entry The #CLIENTMENU object found or nil. -function CLIENTMENUMANAGER:GetEntryByGID(GID) - self:T(self.lid.."GetEntryByGID "..GID or "None") - if GID and type(GID) == "number" then - return self.structure.generic[GID] - else - return nil - end -end - ---- Alter the text of an entry in the generic structure and push to all clients. --- @param #CLIENTMENUMANAGER self --- @param #CLIENTMENU Entry The menu entry. --- @param #string Text Text of the F10 menu entry. --- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:ChangeEntryTextForAll(Entry,Text) - self:T(self.lid.."ChangeEntryTextForAll "..Text or "None") - for _,_client in pairs(self.clientset.Set) do - local client = _client -- Wrapper.Client#CLIENT - if client and client:IsAlive() then - self:ChangeEntryText(Entry,Text, client) - end - end - return self -end - ---- Alter the text of an entry in the generic structure and push to one specific client. --- @param #CLIENTMENUMANAGER self --- @param #CLIENTMENU Entry The menu entry. --- @param #string Text Text of the F10 menu entry. --- @param Wrapper.Client#CLIENT Client The client for whom to alter the entry --- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:ChangeEntryText(Entry,Text, Client) - self:T(self.lid.."ChangeEntryText "..Text or "None") - - local text = Text or "none" - local oldtext = Entry.name - Entry.name = text - - local newstructure = {} - local changed = 0 - - local function ChangePath(path,oldtext,newtext) - local newpath = {} - for _id,_text in UTILS.spairs(path) do - local txt = _text - if _text == oldtext then - txt = newtext - end - newpath[_id] = txt - end - return newpath - end - - local function AlterPath(children) - for _,_entry in pairs(children) do - local entry = _entry -- #CLIENTMENU - local newpath = ChangePath(entry.path,oldtext,text) - local newparentpath = ChangePath(entry.parentpath,oldtext,text) - entry.path = nil - entry.parentpath = nil - entry.path = newpath - entry.parentpath = newparentpath - self:T({entry.ID}) - --self:T({entry.parentpath}) - newstructure[entry.ID] = UTILS.DeepCopy(entry) - changed = changed + 1 - if entry.Children and #entry.Children > 0 then - AlterPath(entry.Children) - end - end - end - - -- get the entry - local ID = Entry.ID - local GID = self.structure.IDs[ID] - local playername = Client:GetPlayerName() - local children = self.structure[playername][GID].Children - AlterPath(children) - - self:T("Changed entries: "..changed) - - local NewParent = self:NewEntry(Entry.name,Entry.Parent,Entry.Function,unpack(Entry.Functionargs)) - - for _,_entry in pairs(children) do - self:T("Changed parent for ".._entry.ID.." | GID ".._entry.GID) - local entry = _entry -- #CLIENTMENU - entry.Parent = NewParent - end - - self:PrepareNewReplacementStructure() - - for _,_entry in pairs(newstructure) do - self:T("Changed entry: ".._entry.ID.." | GID ".._entry.GID) - local entry = _entry -- #CLIENTMENU - self:NewReplacementEntry(entry.name,entry.Parent,entry.Function,unpack(entry.Functionargs)) - end - - - self:AddEntry(NewParent) - self:ReplaceEntries(NewParent) - - self:Clear(Entry) - - return self -end - ---- Create a new entry in the replacement structure. --- @param #CLIENTMENUMANAGER self --- @param #string Text Text of the F10 menu entry. --- @param #CLIENTMENU Parent The parent menu entry. --- @param #string Function (optional) Function to call when the entry is used. --- @param ... (optional) Arguments for the Function, comma separated --- @return #CLIENTMENU Entry -function CLIENTMENUMANAGER:NewReplacementEntry(Text,Parent,Function,...) - self:T(self.lid.."NewReplacementEntry "..Text or "None") - self.entrycount = self.entrycount + 1 - local entry = CLIENTMENU:NewEntry(nil,Text,Parent,Function,unpack(arg)) - self.replacementstructure.generic[self.entrycount] = entry - self.replacementstructure.IDs[entry.ID] = self.entrycount - local pID = Parent and Parent.ID or "none" - if self.debug then - self:I("Entry ID = "..self.entrycount.." | Parent ID = "..tostring(pID)) - end - if not Parent then - self.rootentries[self.entrycount] = self.entrycount - end return entry end ---- Prepare a new replacement structure. Deletes the previous one. +--- Find matching entries by text in the generic structure by UUID. -- @param #CLIENTMENUMANAGER self --- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:PrepareNewReplacementStructure() - self:T(self.lid.."PrepareNewReplacementStructure") - self.replacementstructure = nil -- #CLIENTMENUMANAGER.Structure - self.replacementstructure = { - generic = {}, - IDs = {}, - } - return self -end - ---- [Internal] Merge the replacement structure into the generic structure. --- @param #CLIENTMENUMANAGER self --- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:_MergeReplacementData() - self:T(self.lid.."_MergeReplacementData") - for _id,_entry in pairs(self.replacementstructure.generic) do - self.structure.generic[_id] = _entry - end - for _id,_entry in pairs(self.replacementstructure.IDs) do - self.structure.IDs[_id] = _entry - end - self:_CleanUpPlayerStructure() - return self -end - ---- Replace entries under the Parent entry with the Replacement structure created prior for all clients. --- @param #CLIENTMENUMANAGER self --- @param #CLIENTMENU Parent The parent entry under which to replace with the new structure. --- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. In this case the generic structure will not be touched. --- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:ReplaceEntries(Parent,Client) - self:T(self.lid.."ReplaceEntries") - -- clear Parent substructure - local Set = self.clientset.Set - if Client then - Set = {Client} - else - self:RemoveSubEntries(Parent) - end - for _,_client in pairs(Set) do - local client = _client -- Wrapper.Client#CLIENT - if client and client:IsAlive() then - local playername = client:GetPlayerName() - --self.structure[playername] = {} - for _id,_entry in UTILS.spairs(self.replacementstructure.generic) do - local entry = _entry -- #CLIENTMENU - local parent = Parent - self:T("Posted Parent = "..Parent.ID) - if entry.Parent and entry.Parent.name then - parent = self:_GetParentEntry(self.replacementstructure.generic,entry.Parent.name) or Parent - self:T("Found Parent = "..parent.ID) - end - self.structure[playername][_id] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs)) - self.structure[playername][_id].Once = entry.Once - end +-- @param #string Text Text or partial text of the menu entry to find. +-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry. +-- @return #table Table of matching UUIDs of #CLIENTMENU objects +-- @return #table Table of matching #CLIENTMENU objects +-- @return #number Number of matches +function CLIENTMENUMANAGER:FindUUIDsByText(Text,Parent) + self:T(self.lid.."FindUUIDsByText "..Text or "None") + local matches = {} + local entries = {} + local n = 0 + for _uuid,_entry in pairs(self.flattree) do + local Entry = _entry -- #CLIENTMENU + if Parent then + if Entry and string.find(Entry.name,Text) and string.find(Entry.UUID,Parent.UUID) then + table.insert(matches,_uuid) + table.insert(entries,Entry ) + n=n+1 + end + else + if Entry and string.find(Entry.name,Text) then + table.insert(matches,_uuid) + table.insert(entries,Entry ) + n=n+1 + end end end - self:_MergeReplacementData() + return matches, entries, n +end + +--- Find matching entries in the generic structure by the menu text. +-- @param #CLIENTMENUMANAGER self +-- @param #string Text Text or partial text of the F10 menu entry. +-- @param #CLIENTMENU Parent (Optional) Only find entries under this parent entry. +-- @return #table Table of matching #CLIENTMENU objects. +-- @return #number Number of matches +function CLIENTMENUMANAGER:FindEntriesByText(Text,Parent) + self:T(self.lid.."FindEntriesByText "..Text or "None") + local matches, objects, number = self:FindUUIDsByText(Text, Parent) + return objects, number +end + +--- Find matching entries under a parent in the generic structure by UUID. +-- @param #CLIENTMENUMANAGER self +-- @param #CLIENTMENU Parent Find entries under this parent entry. +-- @return #table Table of matching UUIDs of #CLIENTMENU objects +-- @return #table Table of matching #CLIENTMENU objects +-- @return #number Number of matches +function CLIENTMENUMANAGER:FindUUIDsByParent(Parent) + self:T(self.lid.."FindUUIDsByParent") + local matches = {} + local entries = {} + local n = 0 + for _uuid,_entry in pairs(self.flattree) do + local Entry = _entry -- #CLIENTMENU + if Parent then + if Entry and string.find(Entry.UUID,Parent.UUID) then + table.insert(matches,_uuid) + table.insert(entries,Entry ) + n=n+1 + end + end + end + return matches, entries, n +end + +--- Find matching entries in the generic structure under a parent. +-- @param #CLIENTMENUMANAGER self +-- @param #CLIENTMENU Parent Find entries under this parent entry. +-- @return #table Table of matching #CLIENTMENU objects. +-- @return #number Number of matches +function CLIENTMENUMANAGER:FindEntriesByParent(Parent) + self:T(self.lid.."FindEntriesByParent") + local matches, objects, number = self:FindUUIDsByParent(Parent) + return objects, number +end + +--- Alter the text of a leaf entry in the generic structure and push to one specific client's F10 menu. +-- @param #CLIENTMENUMANAGER self +-- @param #CLIENTMENU Entry The menu entry. +-- @param #string Text New Text of the F10 menu entry. +-- @param Wrapper.Client#CLIENT Client (optional) The client for whom to alter the entry, if nil done for all clients. +-- @return #CLIENTMENUMANAGER self +function CLIENTMENUMANAGER:ChangeEntryText(Entry, Text, Client) + self:T(self.lid.."ChangeEntryText "..Text or "None") + local newentry = CLIENTMENU:NewEntry(nil,Text,Entry.Parent,Entry.Function,unpack(Entry.Functionargs)) + self:DeleteF10Entry(Entry,Client) + self:DeleteGenericEntry(Entry) + if not Entry.Parent then + self.rootentries[self.entrycount] = newentry + end + local depth = #newentry.path + if not self.menutree[depth] then self.menutree[depth] = {} end + table.insert(self.menutree[depth],newentry.UUID) + self.flattree[newentry.UUID] = newentry + self:AddEntry(newentry,Client) return self end ---- [Internal] Find a parent entry in a given structure by name. --- @param #CLIENTMENUMANAGER self --- @param #table Structure Table of entries. --- @param #string Name Name to find. --- @return #CLIENTMENU Entry -function CLIENTMENUMANAGER:_GetParentEntry(Structure,Name) - self:T(self.lid.."_GetParentEntry") - local found = nil - for _,_entry in pairs(Structure) do - local entry = _entry -- #CLIENTMENU - if entry.name == Name then - found = entry - break - end - end - return found -end - ---- Push the complete menu structure to each of the clients in the set. +--- Push the complete menu structure to each of the clients in the set - refresh the menu tree of the clients. -- @param #CLIENTMENUMANAGER self -- @param Wrapper.Client#CLIENT Client (optional) If given, propagate only for this client. -- @return #CLIENTMENU Entry function CLIENTMENUMANAGER:Propagate(Client) self:T(self.lid.."Propagate") + self:T(Client) local Set = self.clientset.Set if Client then - Set = {Set} + Set = {Client} end + self:ResetMenu(Client) for _,_client in pairs(Set) do local client = _client -- Wrapper.Client#CLIENT if client and client:IsAlive() then local playername = client:GetPlayerName() - self.structure[playername] = {} - for _id,_entry in pairs(self.structure.generic) do - local entry = _entry -- #CLIENTMENU - local parent = nil - if entry.Parent and entry.Parent.name then - parent = self:_GetParentEntry(self.structure[playername],entry.Parent.name) + if not self.playertree[playername] then + self.playertree[playername] = {} + end + for level,branch in pairs (self.menutree) do + self:T("Building branch:" .. level) + for _,leaf in pairs(branch) do + self:T("Building leaf:" .. leaf) + local entry = self:FindEntryByUUID(leaf) + if entry then + self:T("Found generic entry:" .. entry.UUID) + local parent = nil + if entry.Parent and entry.Parent.UUID then + parent = self.playertree[playername][entry.Parent.UUID] or self:FindEntryByUUID(entry.Parent.UUID) + end + self.playertree[playername][entry.UUID] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs)) + self.playertree[playername][entry.UUID].Once = entry.Once + else + self:T("NO generic entry for:" .. leaf) + end end - self.structure[playername][_id] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs)) - self.structure[playername][_id].Once = entry.Once end end end @@ -686,85 +613,79 @@ function CLIENTMENUMANAGER:AddEntry(Entry,Client) local client = _client -- Wrapper.Client#CLIENT if client and client:IsAlive() then local playername = client:GetPlayerName() - local entry = Entry -- #CLIENTMENU - local parent = nil - if entry.Parent and entry.Parent.name then - parent = self:_GetParentEntry(self.structure[playername],entry.Parent.name) - end - self.structure[playername][Entry.ID] = CLIENTMENU:NewEntry(client,entry.name,parent,entry.Function,unpack(entry.Functionargs)) - self.structure[playername][Entry.ID].Once = entry.Once + if Entry then + self:T("Adding generic entry:" .. Entry.UUID) + local parent = nil + if not self.playertree[playername] then + self.playertree[playername] = {} + end + if Entry.Parent and Entry.Parent.UUID then + parent = self.playertree[playername][Entry.Parent.UUID] or self:FindEntryByUUID(Entry.Parent.UUID) + end + self.playertree[playername][Entry.UUID] = CLIENTMENU:NewEntry(client,Entry.name,parent,Entry.Function,unpack(Entry.Functionargs)) + self.playertree[playername][Entry.UUID].Once = Entry.Once + else + self:T("NO generic entry given") + end end end return self end ---- Blank out the menu - remove **all root entries** and all entries below from the client's menus, leaving the generic structure untouched. +--- Blank out the menu - remove **all root entries** and all entries below from the client's F10 menus, leaving the generic structure untouched. -- @param #CLIENTMENUMANAGER self --- @param Wrapper.Client#CLIENT Client +-- @param Wrapper.Client#CLIENT Client (optional) If given, remove only for this client. -- @return #CLIENTMENUMANAGER self function CLIENTMENUMANAGER:ResetMenu(Client) self:T(self.lid.."ResetMenu") for _,_entry in pairs(self.rootentries) do - local RootEntry = self.structure.generic[_entry] - if RootEntry then - self:Clear(RootEntry,Client) + --local RootEntry = self.structure.generic[_entry] + if _entry then + self:DeleteF10Entry(_entry,Client) end end return self end ---- Blank out the menu - remove **all root entries** and all entries below from all clients' menus, and **delete** the generic structure. +--- Blank out the menu - remove **all root entries** and all entries below from all clients' F10 menus, and **delete** the generic structure. -- @param #CLIENTMENUMANAGER self -- @return #CLIENTMENUMANAGER self function CLIENTMENUMANAGER:ResetMenuComplete() self:T(self.lid.."ResetMenuComplete") for _,_entry in pairs(self.rootentries) do - local RootEntry = self.structure.generic[_entry] - if RootEntry then - self:Clear(RootEntry) + --local RootEntry = self.structure.generic[_entry] + if _entry then + self:DeleteF10Entry(_entry) end end - self.structure = nil - self.structure = { - generic = {}, - IDs = {}, - } + self.playertree = nil + self.playertree = {} self.rootentries = nil self.rootentries = {} + self.menutree = nil + self.menutree = {} return self end ---- Remove the entry and all entries below the given entry from the client's menus and the generic structure. +--- Remove the entry and all entries below the given entry from the client's F10 menus. -- @param #CLIENTMENUMANAGER self -- @param #CLIENTMENU Entry The entry to remove -- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. In this case the generic structure will not be touched. -- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:Clear(Entry,Client) - self:T(self.lid.."Clear") - local rid = self.structure.IDs[Entry.ID] - if rid then - local generic = self.structure.generic[rid] - local Set = self.clientset.Set - if Client then - Set = {Client} - end - for _,_client in pairs(Set) do - local client = _client -- Wrapper.Client#CLIENT - if client and client:IsAlive() then - local playername = client:GetPlayerName() - local entry = self.structure[playername][rid] -- #CLIENTMENU - if entry then - entry:Clear() - self.structure[playername][rid] = nil - end - end - end - if not Client then - for _id,_entry in pairs(self.structure.generic) do - local entry = _entry -- #CLIENTMENU - if entry and entry.Parent and entry.Parent.ID and entry.Parent.ID == rid then - self.structure.IDs[entry.ID] = nil - entry = nil +function CLIENTMENUMANAGER:DeleteF10Entry(Entry,Client) + self:T(self.lid.."DeleteF10Entry") + local Set = self.clientset.Set + if Client then + Set = {Client} + end + for _,_client in pairs(Set) do + if _client and _client:IsAlive() then + local playername = _client:GetPlayerName() + if self.playertree[playername] then + local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU + if centry then + --self:I("Match for "..Entry.UUID) + centry:Clear() end end end @@ -772,115 +693,87 @@ function CLIENTMENUMANAGER:Clear(Entry,Client) return self end ---- [Internal] Clean up player shadow structure +--- Remove the entry and all entries below the given entry from the generic tree. -- @param #CLIENTMENUMANAGER self +-- @param #CLIENTMENU Entry The entry to remove -- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:_CleanUpPlayerStructure() - self:T(self.lid.."_CleanUpPlayerStructure") - for _,_client in pairs(self.clientset.Set) do - local client = _client -- Wrapper.Client#CLIENT - if client and client:IsAlive() then - local playername = client:GetPlayerName() - local newstructure = {} - for _id, _entry in UTILS.spairs(self.structure[playername]) do - if self.structure.generic[_id] then - newstructure[_id] = _entry - end - end - self.structure[playername] = nil - self.structure[playername] = newstructure +function CLIENTMENUMANAGER:DeleteGenericEntry(Entry) + self:T(self.lid.."DeleteGenericEntry") + + if Entry.Children and #Entry.Children > 0 then + self:RemoveGenericSubEntries(Entry) + end + + local depth = #Entry.path + local uuid = Entry.UUID + + local tbl = UTILS.DeepCopy(self.menutree) + + if tbl[depth] then + for i=depth,#tbl do + --self:I("Level = "..i) + for _id,_uuid in pairs(tbl[i]) do + self:T(_uuid) + if string.find(_uuid,uuid) or _uuid == uuid then + --self:I("Match for ".._uuid) + self.menutree[i][_id] = nil + self.flattree[_uuid] = nil + end + end end end + return self end ---- Remove all entries below the given entry from the clients' menus and the generic structure. +--- Remove all entries below the given entry from the generic tree. -- @param #CLIENTMENUMANAGER self --- @param #CLIENTMENU Entry The menu entry +-- @param #CLIENTMENU Entry The entry where to start. This entry stays. +-- @return #CLIENTMENUMANAGER self +function CLIENTMENUMANAGER:RemoveGenericSubEntries(Entry) + self:T(self.lid.."RemoveGenericSubEntries") + + local depth = #Entry.path + 1 + local uuid = Entry.UUID + + local tbl = UTILS.DeepCopy(self.menutree) + + if tbl[depth] then + for i=depth,#tbl do + self:T("Level = "..i) + for _id,_uuid in pairs(tbl[i]) do + self:T(_uuid) + if string.find(_uuid,uuid) then + self:T("Match for ".._uuid) + self.menutree[i][_id] = nil + self.flattree[_uuid] = nil + end + end + end + end + return self +end + + +--- Remove all entries below the given entry from the client's F10 menus. +-- @param #CLIENTMENUMANAGER self +-- @param #CLIENTMENU Entry The entry where to start. This entry stays. -- @param Wrapper.Client#CLIENT Client (optional) If given, make this change only for this client. In this case the generic structure will not be touched. -- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:RemoveSubEntries(Entry,Client) +function CLIENTMENUMANAGER:RemoveF10SubEntries(Entry,Client) self:T(self.lid.."RemoveSubEntries") - local rid = self.structure.IDs[Entry.ID] - if rid then - local Set = self.clientset.Set - if Client then - Set = {Client} - end - for _,_client in pairs(Set) do - local client = _client -- Wrapper.Client#CLIENT - if client and client:IsAlive() then - local playername = client:GetPlayerName() - local entry = self.structure[playername][rid] -- #CLIENTMENU - if entry then - entry:RemoveSubEntries() - end + local Set = self.clientset.Set + if Client then + Set = {Client} + end + for _,_client in pairs(Set) do + if _client and _client:IsAlive() then + local playername = _client:GetPlayerName() + if self.playertree[playername] then + local centry = self.playertree[playername][Entry.UUID] -- #CLIENTMENU + centry:RemoveSubEntries() end end - if not Client then - for _id,_entry in pairs(self.structure.generic) do - local entry = _entry -- #CLIENTMENU - if entry and entry.Parent and entry.Parent.ID and entry.Parent.ID == rid then - self.structure.IDs[entry.ID] = nil - self.structure.generic[_id] = nil - end - end - end - end - self:_CleanUpPlayerStructure() - return self -end - ---- Remove a specific entry by ID from the generic structure --- @param #CLIENTMENUMANAGER self --- @param #number ID --- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:_RemoveByID(ID) - self:T(self.lid.."_RemoveByID "..ID or "none") - if ID then - local gid = self.structure.IDs[ID] - if gid then - self.structure.generic[gid] = nil - self.structure.IDs[ID] = nil - end - end - return self -end - ---- [Internal] Dump structures to log for debug --- @param #CLIENTMENUMANAGER self --- @param #string Playername --- @return #CLIENTMENUMANAGER self -function CLIENTMENUMANAGER:_CheckStructures(Playername) - self:T(self.lid.."CheckStructures") - self:I("Generic Structure") - self:I("-----------------") - for _id,_entry in UTILS.spairs(self.structure.generic) do - local ID = "none" - if _entry and _entry.ID then - ID = _entry.ID - end - self:I("ID= ".._id.." | EntryID = "..ID) - if _id > 10 and _id < 14 then - self:I(_entry.name) - end - end - self:I("Reverse Structure") - self:I("-----------------") - for _id,_entry in UTILS.spairs(self.structure.IDs) do - self:I("EntryID= ".._id.." | ID = ".._entry) - end - if Playername then - self:I("Player Structure") - self:I("-----------------") - for _id,_entry in UTILS.spairs(self.structure[Playername]) do - local ID = "none" - if _entry and _entry.ID then - ID = _entry.ID - end - local _lid = _id or "none" - self:I("ID= ".._lid.." | EntryID = "..ID) - end end return self end From 8a8e40e810b00f356a321a490eae39c466d661e8 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Mon, 17 Jul 2023 16:27:54 +0200 Subject: [PATCH 2/2] #PLAYERTASK * Refactored menubuilds to use new CLIENTMENU/CLIENTMENUCONTROLLER classes --- Moose Development/Moose/Ops/PlayerTask.lua | 707 ++++++++++++--------- 1 file changed, 402 insertions(+), 305 deletions(-) diff --git a/Moose Development/Moose/Ops/PlayerTask.lua b/Moose Development/Moose/Ops/PlayerTask.lua index a7c127b1f..196e422d0 100644 --- a/Moose Development/Moose/Ops/PlayerTask.lua +++ b/Moose Development/Moose/Ops/PlayerTask.lua @@ -522,7 +522,7 @@ function PLAYERTASK:MarkTargetOnF10Map(Text,Coalition,ReadOnly) -- Marker exists, delete one first self.TargetMarker:Remove() end - local text = Text or "Target of "..self.lid + local text = Text or ("Target of "..self.lid) self.TargetMarker = MARKER:New(coordinate,text) if ReadOnly then self.TargetMarker:ReadOnly() @@ -954,6 +954,7 @@ do -- @field Utilities.FiFo#FIFO TasksPerPlayer -- @field Utilities.FiFo#FIFO PrecisionTasks -- @field Core.Set#SET_CLIENT ClientSet +-- @field Core.Set#SET_CLIENT ActiveClientSet -- @field #string ClientFilter -- @field #string Name -- @field #string Type @@ -988,6 +989,7 @@ do -- @field #table PlayerJoinMenu -- @field #table PlayerInfoMenu -- @field #boolean noflaresmokemenu +-- @field #boolean illumenu -- @field #boolean TransmitOnlyWithPlayers -- @field #boolean buddylasing -- @field Ops.PlayerRecce#PLAYERRECCE PlayerRecce @@ -999,6 +1001,13 @@ do -- @field #table PlayerMenuTag -- @field #boolean UseTypeNames -- @field Functional.Scoring#SCORING Scoring +-- @field Core.ClientMenu#CLIENTMENUMANAGER JoinTaskMenuTemplate +-- @field Core.ClientMenu#CLIENTMENU JoinMenu +-- @field Core.ClientMenu#CLIENTMENU JoinTopMenu +-- @field Core.ClientMenu#CLIENTMENU JoinInfoMenu +-- @field Core.ClientMenu#CLIENTMENUMANAGER ActiveTaskMenuTemplate +-- @field Core.ClientMenu#CLIENTMENU ActiveTopMenu +-- @field Core.ClientMenu#CLIENTMENU ActiveInfoMenu -- @extends Core.Fsm#FSM --- @@ -1155,6 +1164,7 @@ do -- MENUMARK = "Mark on map", -- MENUSMOKE = "Smoke", -- MENUFLARE = "Flare", +-- MENUILLU = "Illuminate", -- MENUABORT = "Abort", -- MENUJOIN = "Join Task", -- MENUTASKINFO = Task Info", @@ -1315,6 +1325,7 @@ PLAYERTASKCONTROLLER = { PlayerInfoMenu = {}, PlayerMenuTag = {}, noflaresmokemenu = false, + illumenu = false, TransmitOnlyWithPlayers = true, buddylasing = false, PlayerRecce = nil, @@ -1408,6 +1419,7 @@ PLAYERTASKCONTROLLER.Messages = { MENUMARK = "Mark on map", MENUSMOKE = "Smoke", MENUFLARE = "Flare", + MENUILLU = "Illuminate", MENUABORT = "Abort", MENUJOIN = "Join Task", MENUTASKINFO = "Task Info", @@ -1487,6 +1499,7 @@ PLAYERTASKCONTROLLER.Messages = { MENUMARK = "Kartenmarkierung", MENUSMOKE = "Rauchgranate", MENUFLARE = "Leuchtgranate", + MENUILLU = "Feldbeleuchtung", MENUABORT = "Abbrechen", MENUJOIN = "Auftrag annehmen", MENUTASKINFO = "Auftrag Briefing", @@ -1592,25 +1605,28 @@ function PLAYERTASKCONTROLLER:New(Name, Coalition, Type, ClientFilter) self.CallsignTranslations = nil self.noflaresmokemenu = false + self.illumenu = false self.ShowMagnetic = true self.UseTypeNames = false - local IsClientSet = false + self.IsClientSet = false if ClientFilter and type(ClientFilter) == "table" and ClientFilter.ClassName and ClientFilter.ClassName == "SET_CLIENT" then -- we have a predefined SET_CLIENT self.ClientSet = ClientFilter - IsClientSet = true + self.IsClientSet = true end - if ClientFilter and not IsClientSet then + if ClientFilter and not self.IsClientSet then self.ClientSet = SET_CLIENT:New():FilterCoalitions(string.lower(self.CoalitionName)):FilterActive(true):FilterPrefixes(ClientFilter):FilterStart() - elseif not IsClientSet then + elseif not self.IsClientSet then self.ClientSet = SET_CLIENT:New():FilterCoalitions(string.lower(self.CoalitionName)):FilterActive(true):FilterStart() end + self.ActiveClientSet = SET_CLIENT:New() + self.lid=string.format("PlayerTaskController %s %s | ", self.Name, tostring(self.Type)) self:_InitLocalization() @@ -1849,6 +1865,24 @@ function PLAYERTASKCONTROLLER:SetEnableSmokeFlareTask() return self end +--- [User] Show menu entries to illuminate targets. Needs smoke/flare enabled. +-- @param #PLAYERTASKCONTROLLER self +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:SetEnableIlluminateTask() + self:T(self.lid.."SetEnableSmokeFlareTask") + self.illumenu = true + return self +end + +--- [User] Do not show menu entries to illuminate targets. +-- @param #PLAYERTASKCONTROLLER self +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:SetDisableIlluminateTask() + self:T(self.lid.."SetDisableIlluminateTask") + self.illumenu = false + return self +end + --- [User] Show info text on screen with a coordinate info in any case (OFF by default) -- @param #PLAYERTASKCONTROLLER self -- @param #boolean OnOff Switch on = true or off = false @@ -2141,6 +2175,7 @@ end -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:_EventHandler(EventData) self:T(self.lid.."_EventHandler: "..EventData.id) + self:T(self.lid.."_EventHandler: "..EventData.IniPlayerName) if EventData.id == EVENTS.PlayerLeaveUnit or EventData.id == EVENTS.Ejection or EventData.id == EVENTS.Crash or EventData.id == EVENTS.PilotDead then if EventData.IniPlayerName then self:T(self.lid.."Event for player: "..EventData.IniPlayerName) @@ -2164,41 +2199,45 @@ function PLAYERTASKCONTROLLER:_EventHandler(EventData) self:T(self.lid..text) end elseif EventData.id == EVENTS.PlayerEnterAircraft and EventData.IniCoalition == self.Coalition then - if EventData.IniPlayerName and EventData.IniGroup and self.UseSRS then - if self.ClientSet:IsNotInSet(CLIENT:FindByName(EventData.IniUnitName)) then + if EventData.IniPlayerName and EventData.IniGroup then + if self.IsClientSet and self.ClientSet:IsNotInSet(CLIENT:FindByName(EventData.IniUnitName)) then + self:T(self.lid.."Client not in SET: "..EventData.IniPlayerName) return self end self:T(self.lid.."Event for player: "..EventData.IniPlayerName) - local frequency = self.Frequency - local freqtext = "" - if type(frequency) == "table" then - freqtext = self.gettext:GetEntry("FREQUENCIES",self.locale) - freqtext = freqtext..table.concat(frequency,", ") - else - local freqt = self.gettext:GetEntry("FREQUENCY",self.locale) - freqtext = string.format(freqt,frequency) - end - local modulation = self.Modulation - if type(modulation) == "table" then modulation = modulation[1] end - modulation = UTILS.GetModulationName(modulation) - local switchtext = self.gettext:GetEntry("BROADCAST",self.locale) - local playername = EventData.IniPlayerName - if EventData.IniGroup then - -- personalized flight name in player naming - if self.customcallsigns[playername] then - self.customcallsigns[playername] = nil + if self.UseSRS then + local frequency = self.Frequency + local freqtext = "" + if type(frequency) == "table" then + freqtext = self.gettext:GetEntry("FREQUENCIES",self.locale) + freqtext = freqtext..table.concat(frequency,", ") + else + local freqt = self.gettext:GetEntry("FREQUENCY",self.locale) + freqtext = string.format(freqt,frequency) end - playername = EventData.IniGroup:GetCustomCallSign(self.ShortCallsign,self.Keepnumber) + local modulation = self.Modulation + if type(modulation) == "table" then modulation = modulation[1] end + modulation = UTILS.GetModulationName(modulation) + local switchtext = self.gettext:GetEntry("BROADCAST",self.locale) + + local playername = EventData.IniPlayerName + if EventData.IniGroup then + -- personalized flight name in player naming + if self.customcallsigns[playername] then + self.customcallsigns[playername] = nil + end + playername = EventData.IniGroup:GetCustomCallSign(self.ShortCallsign,self.Keepnumber) + end + playername = self:_GetTextForSpeech(playername) + --local text = string.format("%s, %s, switch to %s for task assignment!",EventData.IniPlayerName,self.MenuName or self.Name,freqtext) + local text = string.format(switchtext,playername,self.MenuName or self.Name,freqtext) + self.SRSQueue:NewTransmission(text,nil,self.SRS,timer.getAbsTime()+60,2,{EventData.IniGroup},text,30,self.BCFrequency,self.BCModulation) end - playername = self:_GetTextForSpeech(playername) - --local text = string.format("%s, %s, switch to %s for task assignment!",EventData.IniPlayerName,self.MenuName or self.Name,freqtext) - local text = string.format(switchtext,playername,self.MenuName or self.Name,freqtext) - self.SRSQueue:NewTransmission(text,nil,self.SRS,timer.getAbsTime()+60,2,{EventData.IniGroup},text,30,self.BCFrequency,self.BCModulation) if EventData.IniPlayerName then self.PlayerMenu[EventData.IniPlayerName] = nil - --self:_BuildMenus(CLIENT:FindByName(EventData.IniUnitName)) - self:_BuildMenus(CLIENT:FindByPlayerName(EventData.IniPlayerName)) + local player = CLIENT:FindByName(EventData.IniUnitName) + self:_SwitchMenuForClient(player,"Info") end end end @@ -2308,7 +2347,7 @@ function PLAYERTASKCONTROLLER:_GetTasksPerType() self:T(self.lid.."_GetTasksPerType") local tasktypes = self:_GetAvailableTaskTypes() - --self:T({tasktypes}) + --self:I({tasktypes}) -- Sort tasks per threat level first local datatable = self.TaskQueue:GetDataTable() @@ -2327,11 +2366,23 @@ function PLAYERTASKCONTROLLER:_GetTasksPerType() local threat=_data.threat local task = _data.task -- Ops.PlayerTask#PLAYERTASK local type = task.Type + local name = task.Target:GetName() + --self:I(name) if not task:IsDone() then + --self:I(name) table.insert(tasktypes[type],task) end end + --[[ + for _type,_data in pairs(tasktypes) do + self:I("Task Type: ".._type) + for _id,_task in pairs(_data) do + self:I("Task Name: ".._task.Target:GetName()) + end + end + --]] + return tasktypes end @@ -2443,7 +2494,7 @@ function PLAYERTASKCONTROLLER:_CheckTaskQueue() local client = _client --Wrapper.Client#CLIENT local group = client:GetGroup() for _,task in pairs(nexttasks) do - self:_JoinTask(group,client,task,true) + self:_JoinTask(task,true,group,client) end end end @@ -2462,7 +2513,7 @@ end -- @param #PLAYERTASKCONTROLLER self -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:_CheckPrecisionTasks() - self:T(self.lid.."_CheckTaskQueue") + self:T(self.lid.."_CheckPrecisionTasks") if self.PrecisionTasks:Count() > 0 and self.precisionbombing then if not self.LasingDrone or self.LasingDrone:IsDead() then -- we need a new drone @@ -2965,15 +3016,20 @@ end --- [Internal] Join a player to a task -- @param #PLAYERTASKCONTROLLER self --- @param Wrapper.Group#GROUP Group --- @param Wrapper.Client#CLIENT Client -- @param Ops.PlayerTask#PLAYERTASK Task -- @param #boolean Force Assign task even if client already has one +-- @param Wrapper.Group#GROUP Group +-- @param Wrapper.Client#CLIENT Client -- @return #PLAYERTASKCONTROLLER self -function PLAYERTASKCONTROLLER:_JoinTask(Group, Client, Task, Force) +function PLAYERTASKCONTROLLER:_JoinTask(Task, Force, Group, Client) + self:T({Force, Group, Client}) self:T(self.lid.."_JoinTask") + local force = false + if type(Force) == "boolean" then + force = Force + end local playername, ttsplayername = self:_GetPlayerName(Client) - if self.TasksPerPlayer:HasUniqueID(playername) and not Force then + if self.TasksPerPlayer:HasUniqueID(playername) and not force then -- Player already has a task if not self.NoScreenOutput then local text = self.gettext:GetEntry("HAVEACTIVETASK",self.locale) @@ -3004,7 +3060,7 @@ function PLAYERTASKCONTROLLER:_JoinTask(Group, Client, Task, Force) self.TasksPerPlayer:Push(Task,playername) self:__PlayerJoinedTask(1, Group, Client, Task) -- clear menu - self:_BuildMenus(Client,true) + self:_SwitchMenuForClient(Client,"Active",1) end if Task.Type == AUFTRAG.Type.PRECISIONBOMBING then if not self.PrecisionTasks:HasUniqueID(Task.PlayerTaskNr) then @@ -3065,19 +3121,23 @@ end --- [Internal] Show active task info -- @param #PLAYERTASKCONTROLLER self +-- @param Ops.PlayerTask#PLAYERTASK Task -- @param Wrapper.Group#GROUP Group -- @param Wrapper.Client#CLIENT Client --- @param Ops.PlayerTask#PLAYERTASK Task -- @return #PLAYERTASKCONTROLLER self -function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Group, Client, Task) +function PLAYERTASKCONTROLLER:_ActiveTaskInfo(Task, Group, Client) self:T(self.lid.."_ActiveTaskInfo") local playername, ttsplayername = self:_GetPlayerName(Client) local text = "" local textTTS = "" - if self.TasksPerPlayer:HasUniqueID(playername) or Task then + local task = nil + if type(Task) ~= "string" then + task = Task + end + if self.TasksPerPlayer:HasUniqueID(playername) or task then -- NODO: Show multiple? -- Details - local task = Task or self.TasksPerPlayer:ReadByID(playername) -- Ops.PlayerTask#PLAYERTASK + local task = task or self.TasksPerPlayer:ReadByID(playername) -- Ops.PlayerTask#PLAYERTASK local tname = self.gettext:GetEntry("TASKNAME",self.locale) local ttsname = self.gettext:GetEntry("TASKNAMETTS",self.locale) local taskname = string.format(tname,task.Type,task.PlayerTaskNr) @@ -3389,280 +3449,287 @@ function PLAYERTASKCONTROLLER:_AbortTask(Group, Client) if not self.NoScreenOutput then local m=MESSAGE:New(text,15,"Tasking"):ToClient(Client) end - self:_BuildMenus(Client,true) + self:_SwitchMenuForClient(Client,"Info",1) return self end ---- [Internal] Build Task Info Menu + +-- TODO - New Menu Manager +--- [Internal] _UpdateJoinMenuTemplate -- @param #PLAYERTASKCONTROLLER self --- @param Wrapper.Group#GROUP group --- @param Wrapper.Client#CLIENT client --- @param #string playername --- @param Core.Menu#MENU_BASE topmenu --- @param #table tasktypes --- @param #table taskpertype --- @param #string newtag --- @return #table taskinfomenu -function PLAYERTASKCONTROLLER:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype,newtag) - self:T(self.lid.."_BuildTaskInfoMenu") - local taskinfomenu = nil - if self.taskinfomenu then - local menutaskinfo = self.gettext:GetEntry("MENUTASKINFO",self.locale) - local taskinfomenu = MENU_GROUP:New(group,menutaskinfo,topmenu):SetTag(newtag) - local ittypes = {} - local itaskmenu = {} - local tnow = timer.getTime() - - for _tasktype,_data in pairs(tasktypes) do - ittypes[_tasktype] = MENU_GROUP:New(group,_tasktype,taskinfomenu):SetTag(newtag) - local tasks = taskpertype[_tasktype] or {} - local n = 0 - for _,_task in pairs(tasks) do - _task = _task -- Ops.PlayerTask#PLAYERTASK - local pilotcount = _task:CountClients() - local newtext = "]" - -- marker for new tasks - if tnow - _task.timestamp < 60 then - newtext = "*]" +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:_UpdateJoinMenuTemplate() + self:T("_UpdateJoinMenuTemplate") + if self.TaskQueue:Count() > 0 then + local taskpertype = self:_GetTasksPerType() + local JoinMenu = self.JoinMenu -- Core.ClientMenu#CLIENTMENU + --self:I(JoinMenu.UUID) + local controller = self.JoinTaskMenuTemplate -- Core.ClientMenu#CLIENTMENUMANAGER + local actcontroller = self.ActiveTaskMenuTemplate -- Core.ClientMenu#CLIENTMENUMANAGER + local actinfomenu = self.ActiveInfoMenu + --local entrynumbers = {} + --local existingentries = {} + local maxn = self.menuitemlimit + -- Generate task type menu items + for _type,_ in pairs(taskpertype) do + local found = controller:FindEntriesByText(_type) + --self:I({found}) + if #found == 0 then + local newentry = controller:NewEntry(_type,JoinMenu) + controller:AddEntry(newentry) + if self.JoinInfoMenu then + local newentry = controller:NewEntry(_type,self.JoinInfoMenu) + controller:AddEntry(newentry) end - local menutaskno = self.gettext:GetEntry("MENUTASKNO",self.locale) - local text = string.format("%s %03d [%d%s",menutaskno,_task.PlayerTaskNr,pilotcount,newtext) - if self.UseGroupNames then - local name = _task.Target:GetName() - if name ~= "Unknown" then - text = string.format("%s (%03d) [%d%s",name,_task.PlayerTaskNr,pilotcount,newtext) - end + if actinfomenu then + local newentry = actcontroller:NewEntry(_type,self.ActiveInfoMenu) + actcontroller:AddEntry(newentry) end - if self.UseTypeNames then - if _task.TypeName then - --local name = self.gettext:GetEntry(_task.TypeName,self.locale) - text = string.format("%s (%03d) [%d%s",_task.TypeName,_task.PlayerTaskNr,pilotcount,newtext) - --self:T(self.lid.."Menu text = "..text) - end - end - local taskentry = MENU_GROUP_COMMAND:New(group,text,ittypes[_tasktype],self._ActiveTaskInfo,self,group,client,_task):SetTag(newtag) - --taskentry:SetTag(playername) - itaskmenu[#itaskmenu+1] = taskentry - -- keep max items limit - n = n + 1 - if n >= self.menuitemlimit then - break - end end end + + local typelist = self:_GetAvailableTaskTypes() + -- Slot in Tasks + for _tasktype,_data in pairs(typelist) do + self:T("**** Building for TaskType: ".._tasktype) + --local tasks = taskpertype[_tasktype] or {} + for _,_task in pairs(taskpertype[_tasktype]) do + _task = _task -- Ops.PlayerTask#PLAYERTASK + self:T("**** Building for Task: ".._task.Target:GetName()) + if _task.InMenu then + self:T("**** Task already in Menu ".._task.Target:GetName()) + else + --local pilotcount = _task:CountClients() + --local newtext = "]" + --local tnow = timer.getTime() + -- marker for new tasks + --if tnow - _task.timestamp < 60 then + --newtext = "*]" + --end + local menutaskno = self.gettext:GetEntry("MENUTASKNO",self.locale) + --local text = string.format("%s %03d [%d%s",menutaskno,_task.PlayerTaskNr,pilotcount,newtext) + local text = string.format("%s %03d",menutaskno,_task.PlayerTaskNr) + if self.UseGroupNames then + local name = _task.Target:GetName() + if name ~= "Unknown" then + --text = string.format("%s (%03d) [%d%s",name,_task.PlayerTaskNr,pilotcount,newtext) + text = string.format("%s (%03d)",name,_task.PlayerTaskNr) + end + end + --local taskentry = MENU_GROUP_COMMAND:New(group,text,ttypes[_tasktype],self._JoinTask,self,group,client,_task):SetTag(newtag) + local parenttable, number = controller:FindEntriesByText(_tasktype,JoinMenu) + if number > 0 then + local Parent = parenttable[1] + local matches, count = controller:FindEntriesByParent(Parent) + self:T("***** Join Menu ".._tasktype.. " # of entries: "..count) + if count < self.menuitemlimit then + local taskentry = controller:NewEntry(text,Parent,self._JoinTask,self,_task,"false") + controller:AddEntry(taskentry) + _task.InMenu = true + if not _task.UUIDS then _task.UUIDS = {} end + table.insert(_task.UUIDS,taskentry.UUID) + end + end + if self.JoinInfoMenu then + local parenttable, number = controller:FindEntriesByText(_tasktype,self.JoinInfoMenu) + if number > 0 then + local Parent = parenttable[1] + local matches, count = controller:FindEntriesByParent(Parent) + self:T("***** Join Info Menu ".._tasktype.. " # of entries: "..count) + if count < self.menuitemlimit then + local taskentry = controller:NewEntry(text,Parent,self._ActiveTaskInfo,self,_task) + controller:AddEntry(taskentry) + _task.InMenu = true + if not _task.UUIDS then _task.UUIDS = {} end + table.insert(_task.UUIDS,taskentry.UUID) + end + end + end + if actinfomenu then + local parenttable, number = actcontroller:FindEntriesByText(_tasktype,self.ActiveInfoMenu) + if number > 0 then + local Parent = parenttable[1] + local matches, count = actcontroller:FindEntriesByParent(Parent) + self:T("***** Active Info Menu ".._tasktype.. " # of entries: "..count) + if count < self.menuitemlimit then + local taskentry = actcontroller:NewEntry(text,Parent,self._ActiveTaskInfo,self,_task) + actcontroller:AddEntry(taskentry) + _task.InMenu = true + if not _task.AUUIDS then _task.AUUIDS = {} end + table.insert(_task.AUUIDS,taskentry.UUID) + end + end + end + end + end + end end - return taskinfomenu + return self end ---- [Internal] Build client menus +--- [Internal] _RemoveMenuEntriesForTask -- @param #PLAYERTASKCONTROLLER self --- @param Wrapper.Client#CLIENT Client (optional) build for this client name only --- @param #boolean enforced --- @param #boolean fromsuccess +-- @param #PLAYERTASK Task +-- @param Wrapper.Client#CLIENT Client -- @return #PLAYERTASKCONTROLLER self -function PLAYERTASKCONTROLLER:_BuildMenus(Client,enforced,fromsuccess) - self:T(self.lid.."_BuildMenus") - - if self.MenuBuildLocked and (timer.getAbsTime() - self.MenuBuildLocked < 2) then - self:ScheduleOnce(2,self._BuildMenus,self,Client,enforced,fromsuccess) - return self - else - self.MenuBuildLocked = timer.getAbsTime() - end - - local clients = self.ClientSet:GetAliveSet() - local joinorabort = false - local timedbuild = false - - if Client then - -- client + enforced -- join task or abort - clients = {Client} - enforced = true - joinorabort = true - end - - local tasktypes = self:_GetAvailableTaskTypes() - local taskpertype = self:_GetTasksPerType() - - for _,_client in pairs(clients) do - if _client and _client:IsAlive() then - local client = _client -- Wrapper.Client#CLIENT - local group = client:GetGroup() - local unknown = self.gettext:GetEntry("UNKNOWN",self.locale) - local playername = client:GetPlayerName() or unknown - - local oldtag = self.PlayerMenuTag[playername] - local newtag = playername..timer.getAbsTime() - self.PlayerMenuTag[playername] = newtag - - if group and client then - --- - -- TOPMENU - --- - local taskings = self.gettext:GetEntry("MENUTASKING",self.locale) - local longname = self.Name..taskings..self.Type - local menuname = self.MenuName or longname - local playerhastask = false - - if self:_CheckPlayerHasTask(playername) and not fromsuccess then playerhastask = true end - local topmenu = nil - --local oldmenu = nil - local rebuilddone = false - - self:T("Playerhastask = "..tostring(playerhastask).." Enforced = "..tostring(enforced).." Join or Abort = "..tostring(joinorabort)) - - -- Cases to rebuild menu - -- 1) new player - -- 2) player joined a task, joinorabort = true - -- 3) player left a task, joinorabort = true - -- 4) player has no task, but number of tasks changed, and last build > 30 secs ago - if self.PlayerMenu[playername] then - -- NOT a new player - -- 2)+3) Join or abort? - if joinorabort then - self.PlayerMenu[playername]:RemoveSubMenus() - self.PlayerMenu[playername] = MENU_GROUP:New(group,menuname,self.MenuParent) - self.PlayerMenu[playername]:SetTag(newtag) - topmenu = self.PlayerMenu[playername] - elseif (not playerhastask) or enforced then - -- 4) last build > 30 secs? - local T0 = timer.getAbsTime() - local TDiff = T0-self.PlayerMenu[playername].PTTimeStamp - self:T("TDiff = "..string.format("%.2d",TDiff)) - if TDiff >= self.holdmenutime then - --self.PlayerMenu[playername]:RemoveSubMenus() - --oldmenu = self.PlayerMenu[playername] - --self.PlayerMenu[playername] = nil - - --self.PlayerMenu[playername]:RemoveSubMenus() - --self.PlayerMenu[playername] = MENU_GROUP:New(group,menuname,self.MenuParent) - --self.PlayerMenu[playername]:SetTag(newtag) - --self.PlayerMenu[playername].PTTimeStamp = timer.getAbsTime() - --timedbuild = true - end - topmenu = self.PlayerMenu[playername] - end - else - -- 1) new player# - topmenu = MENU_GROUP:New(group,menuname,self.MenuParent) - self.PlayerMenu[playername] = topmenu - self.PlayerMenu[playername]:SetTag(newtag) - self.PlayerMenu[playername].PTTimeStamp = timer.getAbsTime() - enforced = true +function PLAYERTASKCONTROLLER:_RemoveMenuEntriesForTask(Task,Client) + self:T("_RemoveMenuEntriesForTask") + --self:I("Task name: "..Task.Target:GetName()) + --self:I("Client: "..Client:GetPlayerName()) + if Task then + if Task.UUIDS and self.JoinTaskMenuTemplate then + --self:I("***** JoinTaskMenuTemplate") + UTILS.PrintTableToLog(Task.UUIDS) + local controller = self.JoinTaskMenuTemplate + for _,_uuid in pairs(Task.UUIDS) do + local Entry = controller:FindEntryByUUID(_uuid) + if Entry then + controller:DeleteF10Entry(Entry,Client) + controller:DeleteGenericEntry(Entry) + UTILS.PrintTableToLog(controller.menutree) end - - --- - -- ACTIVE TASK MENU - --- - if playerhastask and enforced then - self:T("Building Active Task Menus for "..playername) - rebuilddone = true - local menuactive = self.gettext:GetEntry("MENUACTIVE",self.locale) - local menuinfo = self.gettext:GetEntry("MENUINFO",self.locale) - local menumark = self.gettext:GetEntry("MENUMARK",self.locale) - local menusmoke = self.gettext:GetEntry("MENUSMOKE",self.locale) - local menuflare = self.gettext:GetEntry("MENUFLARE",self.locale) - local menuabort = self.gettext:GetEntry("MENUABORT",self.locale) - - local active = MENU_GROUP:New(group,menuactive,topmenu):SetTag(newtag) - local info = MENU_GROUP_COMMAND:New(group,menuinfo,active,self._ActiveTaskInfo,self,group,client):SetTag(newtag) - local mark = MENU_GROUP_COMMAND:New(group,menumark,active,self._MarkTask,self,group,client):SetTag(newtag) - if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A then - if self.noflaresmokemenu ~= true then - -- no smoking/flaring here if A2A or designer has set noflaresmokemenu to true - local smoke = MENU_GROUP_COMMAND:New(group,menusmoke,active,self._SmokeTask,self,group,client):SetTag(newtag) - local flare = MENU_GROUP_COMMAND:New(group,menuflare,active,self._FlareTask,self,group,client):SetTag(newtag) - local IsNight = client:GetCoordinate():IsNight() - if IsNight then - local light = MENU_GROUP_COMMAND:New(group,menuflare,active,self._IlluminateTask,self,group,client):SetTag(newtag) - end - end - end - local abort = MENU_GROUP_COMMAND:New(group,menuabort,active,self._AbortTask,self,group,client):SetTag(newtag) - if self.activehasinfomenu and self.taskinfomenu then - self:T("Building Active-Info Menus for "..playername) - if self.PlayerInfoMenu[playername] then - self.PlayerInfoMenu[playername]:RemoveSubMenus(nil,oldtag) - end - self.PlayerInfoMenu[playername] = self:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype,newtag) - end - elseif (self.TaskQueue:Count() > 0 and enforced) or (not playerhastask and (timedbuild or joinorabort)) then - self:T("Building Join Menus for "..playername) - rebuilddone = true - --- - -- JOIN TASK MENU - --- - local menujoin = self.gettext:GetEntry("MENUJOIN",self.locale) - - if self.PlayerJoinMenu[playername] then - self.PlayerJoinMenu[playername]:RemoveSubMenus(nil,oldtag) - end - - local joinmenu = MENU_GROUP:New(group,menujoin,topmenu):SetTag(newtag) - self.PlayerJoinMenu[playername] = joinmenu - - local ttypes = {} - local taskmenu = {} - for _tasktype,_data in pairs(tasktypes) do - ttypes[_tasktype] = MENU_GROUP:New(group,_tasktype,joinmenu):SetTag(newtag) - local tasks = taskpertype[_tasktype] or {} - local n = 0 - for _,_task in pairs(tasks) do - _task = _task -- Ops.PlayerTask#PLAYERTASK - local pilotcount = _task:CountClients() - local newtext = "]" - local tnow = timer.getTime() - -- marker for new tasks - if tnow - _task.timestamp < 60 then - newtext = "*]" - end - local menutaskno = self.gettext:GetEntry("MENUTASKNO",self.locale) - local text = string.format("%s %03d [%d%s",menutaskno,_task.PlayerTaskNr,pilotcount,newtext) - if self.UseGroupNames then - local name = _task.Target:GetName() - if name ~= "Unknown" then - text = string.format("%s (%03d) [%d%s",name,_task.PlayerTaskNr,pilotcount,newtext) - end - end - local taskentry = MENU_GROUP_COMMAND:New(group,text,ttypes[_tasktype],self._JoinTask,self,group,client,_task):SetTag(newtag) - --taskentry:SetTag(playername) - taskmenu[#taskmenu+1] = taskentry - n = n + 1 - if n >= self.menuitemlimit then - break - end - end - end - if self.taskinfomenu then - self:T("Building Join-Info Menus for "..playername) - if self.PlayerInfoMenu[playername] then - self.PlayerInfoMenu[playername]:RemoveSubMenus(nil,oldtag) - end - self.PlayerInfoMenu[playername] = self:_BuildTaskInfoMenu(group,client,playername,topmenu,tasktypes,taskpertype,newtag) - end - end - if self.AllowFlash and topmenu ~= nil then - local flashtext = self.gettext:GetEntry("FLASHMENU",self.locale) - local flashmenu = MENU_GROUP_COMMAND:New(group,flashtext,topmenu,self._SwitchFlashing,self,group,client):SetTag(newtag) - end - if self.TaskQueue:Count() == 0 then - self:T("No open tasks info") - local menunotasks = self.gettext:GetEntry("MENUNOTASKS",self.locale) - local joinmenu = MENU_GROUP:New(group,menunotasks,self.PlayerMenu[playername]):SetTag(newtag) - rebuilddone = true - end - --- - -- REFRESH MENU - --- - if rebuilddone then - --self.PlayerMenu[playername]:RemoveSubMenus(nil,oldtag) - --self.PlayerMenu[playername]:Set() - self.PlayerMenu[playername]:Refresh() - end end end + + if Task.AUUIDS and self.ActiveTaskMenuTemplate then + --self:I("***** ActiveTaskMenuTemplate") + UTILS.PrintTableToLog(Task.AUUIDS) + for _,_uuid in pairs(Task.AUUIDS) do + local controller = self.ActiveTaskMenuTemplate + local Entry = controller:FindEntryByUUID(_uuid) + if Entry then + controller:DeleteF10Entry(Entry,Client) + controller:DeleteGenericEntry(Entry) + UTILS.PrintTableToLog(controller.menutree) + end + end + end + + Task.UUIDS = nil + Task.AUUIDS = nil + end + return self +end + +--- [Internal] _CreateJoinMenuTemplate +-- @param #PLAYERTASKCONTROLLER self +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:_CreateJoinMenuTemplate() + self:T("_CreateActiveTaskMenuTemplate") + + local menujoin = self.gettext:GetEntry("MENUJOIN",self.locale) + local menunotasks = self.gettext:GetEntry("MENUNOTASKS",self.locale) + local flashtext = self.gettext:GetEntry("FLASHMENU",self.locale) + + local JoinTaskMenuTemplate = CLIENTMENUMANAGER:New(self.ClientSet,"JoinTask") + + if not self.JoinTopMenu then + local taskings = self.gettext:GetEntry("MENUTASKING",self.locale) + local longname = self.Name..taskings..self.Type + local menuname = self.MenuName or longname + self.JoinTopMenu = JoinTaskMenuTemplate:NewEntry(menuname,self.MenuParent) + end + + if self.AllowFlash then + JoinTaskMenuTemplate:NewEntry(flashtext,self.JoinTopMenu,self._SwitchFlashing,self) + end + + self.JoinMenu = JoinTaskMenuTemplate:NewEntry(menujoin,self.JoinTopMenu) + + if self.taskinfomenu then + local menutaskinfo = self.gettext:GetEntry("MENUTASKINFO",self.locale) + self.JoinInfoMenu = JoinTaskMenuTemplate:NewEntry(menutaskinfo,self.JoinTopMenu) + end + + if self.TaskQueue:Count() == 0 then + JoinTaskMenuTemplate:NewEntry(menunotasks,self.JoinMenu) + end + + self.JoinTaskMenuTemplate = JoinTaskMenuTemplate + + return self +end + +--- [Internal] _CreateActiveTaskMenuTemplate +-- @param #PLAYERTASKCONTROLLER self +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:_CreateActiveTaskMenuTemplate() + self:T("_CreateActiveTaskMenuTemplate") + + local menuactive = self.gettext:GetEntry("MENUACTIVE",self.locale) + local menuinfo = self.gettext:GetEntry("MENUINFO",self.locale) + local menumark = self.gettext:GetEntry("MENUMARK",self.locale) + local menusmoke = self.gettext:GetEntry("MENUSMOKE",self.locale) + local menuflare = self.gettext:GetEntry("MENUFLARE",self.locale) + local menuillu = self.gettext:GetEntry("MENUILLU",self.locale) + local menuabort = self.gettext:GetEntry("MENUABORT",self.locale) + + local ActiveTaskMenuTemplate = CLIENTMENUMANAGER:New(self.ActiveClientSet,"ActiveTask") + + if not self.ActiveTopMenu then + local taskings = self.gettext:GetEntry("MENUTASKING",self.locale) + local longname = self.Name..taskings..self.Type + local menuname = self.MenuName or longname + self.ActiveTopMenu = ActiveTaskMenuTemplate:NewEntry(menuname,self.MenuParent) + end + + if self.AllowFlash then + local flashtext = self.gettext:GetEntry("FLASHMENU",self.locale) + ActiveTaskMenuTemplate:NewEntry(flashtext,self.ActiveTopMenu,self._SwitchFlashing,self) + end + + local active = ActiveTaskMenuTemplate:NewEntry(menuactive,self.ActiveTopMenu) + ActiveTaskMenuTemplate:NewEntry(menuinfo,active,self._ActiveTaskInfo,self,"NONE") + ActiveTaskMenuTemplate:NewEntry(menumark,active,self._MarkTask,self) + + if self.Type ~= PLAYERTASKCONTROLLER.Type.A2A and self.noflaresmokemenu ~= true then + ActiveTaskMenuTemplate:NewEntry(menusmoke,active,self._SmokeTask,self) + ActiveTaskMenuTemplate:NewEntry(menuflare,active,self._FlareTask,self) + + if self.illumenu then + ActiveTaskMenuTemplate:NewEntry(menuillu,active,self._IlluminateTask,self) + end + + end + + ActiveTaskMenuTemplate:NewEntry(menuabort,active,self._AbortTask,self) + self.ActiveTaskMenuTemplate = ActiveTaskMenuTemplate + + if self.taskinfomenu and self.activehasinfomenu then + local menutaskinfo = self.gettext:GetEntry("MENUTASKINFO",self.locale) + self.ActiveInfoMenu = ActiveTaskMenuTemplate:NewEntry(menutaskinfo,self.ActiveTopMenu) + end + + return self +end + +--- [Internal] _SwitchMenuForClient +-- @param #PLAYERTASKCONTROLLER self +-- @param Wrapper.Client#CLIENT Client The client +-- @param #string MenuType +-- @param #number Delay +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:_SwitchMenuForClient(Client,MenuType,Delay) + self:T(self.lid.."_SwitchMenuForClient") + if Delay then + self:ScheduleOnce(Delay,self._SwitchMenuForClient,self,Client,MenuType) + return self + end + if MenuType == "Info" then + self.ClientSet:AddClientsByName(Client:GetName()) + self.ActiveClientSet:Remove(Client:GetName(),true) + self.ActiveTaskMenuTemplate:ResetMenu(Client) + self.JoinTaskMenuTemplate:ResetMenu(Client) + self.JoinTaskMenuTemplate:Propagate(Client) + elseif MenuType == "Active" then + self.ActiveClientSet:AddClientsByName(Client:GetName()) + self.ClientSet:Remove(Client:GetName(),true) + self.ActiveTaskMenuTemplate:ResetMenu(Client) + self.JoinTaskMenuTemplate:ResetMenu(Client) + self.ActiveTaskMenuTemplate:Propagate(Client) + else + self:E(self.lid .."Unknown menu type in _SwitchMenuForClient:"..tostring(MenuType)) end - self.MenuBuildLocked = false return self end @@ -3810,8 +3877,8 @@ end -- @param Core.Menu#MENU_MISSION Menu -- @return #PLAYERTASKCONTROLLER self function PLAYERTASKCONTROLLER:SetParentMenu(Menu) - self:T(self.lid.."SetParentName") - self.MenuParent = Menu + self:T(self.lid.."SetParentMenu") + --self.MenuParent = Menu return self end @@ -3965,6 +4032,20 @@ end -- TODO: FSM Functions PLAYERTASKCONTROLLER ------------------------------------------------------------------------------------------------------------------- +--- [Internal] On after start call +-- @param #PLAYERTASKCONTROLLER self +-- @param #string From +-- @param #string Event +-- @param #string To +-- @return #PLAYERTASKCONTROLLER self +function PLAYERTASKCONTROLLER:onafterStart(From, Event, To) + self:T({From, Event, To}) + self:T(self.lid.."onafterStart") + self:_CreateJoinMenuTemplate() + self:_CreateActiveTaskMenuTemplate() + return self +end + --- [Internal] On after Status call -- @param #PLAYERTASKCONTROLLER self -- @param #string From @@ -3994,7 +4075,7 @@ function PLAYERTASKCONTROLLER:onafterStatus(From, Event, To) end end - self:_BuildMenus(nil,enforcedmenu) + self:_UpdateJoinMenuTemplate() if self.verbose then local text = string.format("%s | New Targets: %02d | Active Tasks: %02d | Active Players: %02d | Assigned Tasks: %02d",self.MenuName, targetcount,taskcount,playercount,assignedtasks) @@ -4041,6 +4122,16 @@ function PLAYERTASKCONTROLLER:onafterTaskCancelled(From, Event, To, Task) taskname = string.format(canceltxttts, self.MenuName or self.Name, Task.PlayerTaskNr, tostring(Task.TTSType)) self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2) end + + local clients=Task:GetClientObjects() + for _,client in pairs(clients) do + self:_RemoveMenuEntriesForTask(Task,client) + --self:_SwitchMenuForClient(client,"Info") + end + for _,client in pairs(clients) do + --self:_RemoveMenuEntriesForTask(Task,client) + self:_SwitchMenuForClient(client,"Info",5) + end return self end @@ -4065,9 +4156,15 @@ function PLAYERTASKCONTROLLER:onafterTaskSuccess(From, Event, To, Task) taskname = string.format(succtxttts, self.MenuName or self.Name, Task.PlayerTaskNr, tostring(Task.TTSType)) self.SRSQueue:NewTransmission(taskname,nil,self.SRS,nil,2) end + local clients=Task:GetClientObjects() for _,client in pairs(clients) do - self:_BuildMenus(client,true,true) + self:_RemoveMenuEntriesForTask(Task,client) + --self:_SwitchMenuForClient(client,"Info") + end + for _,client in pairs(clients) do + -- self:_RemoveMenuEntriesForTask(Task,client) + self:_SwitchMenuForClient(client,"Info",5) end return self end