View topic - Send table from Synced Gadget -> Widget



All times are UTC + 1 hour


Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: 15 Feb 2012, 17:47 

Joined: 10 Feb 2012, 23:20
Hey all,

I'm currently working on improving the UI for my mod using Chili.

I have a synced gadget that maintains a queue of actions that can only be run in sequential order during gameplay. This queue is currently stored as a table (of subtables). I want to display this queue via Chili labels. I have the Chili framework set up and prepared to update.

My roadblock is that I can't seem to get the information past the synced/unsynced barrier. I've managed to do this with within the same gadget before, but this is communication from a synced gadget->widget and the data I'm sending is more complex than a single variable.

Does anybody know how I can pass this information?


Top
 Offline Profile  
 
PostPosted: 15 Feb 2012, 18:00 
Content Developer
User avatar

Joined: 13 Jan 2005, 00:46
Location: ModalitÃ
Code:
function gadget:GetInfo()
   return {
      name      = "Gundam scoring",
      desc      = "sets high score for players",
      author      = "Smoth",
      date      = "(9/3/2001",
      license       = "PD",
      layer       = 0,
      enabled       = true
   }
end

--------------------------------------------------------------------------------------------------
-- Special thanks to jk, jools and fatcontroller for data that I needed
--------------------------------------------------------------------------------------------------

local GetTeamList         = Spring.GetTeamList
local GetTeamInfo         = Spring.GetTeamInfo
local AreTeamsAllied      = Spring.AreTeamsAllied
local Echo               = Spring.Echo

-- vanity numbers
local playerScores         = {}
local playerKills         = {}
local playerUnitKills      = {}
local playerDeaths         = {}
local playerDamageTaken      = {}
local playerDamageDealt      = {}

-- for experience system
local playerExperience      = {}
local playerLevelRank      = {}

local levels = VFS.Include("gamedata/ranks.lua")


-- store values for player ranks
local rankList            = {}

local playerLeadKills      = 0
local playerLeadID         = 0

local showScoresOnce      = true
local startRank            = 1

if (gadgetHandler:IsSyncedCode()) then
   -- BEGIN SYNCED
   function gadget:UnitDamaged(unitID, unitDefID, teamID, damage, paralyzer, weaponID, attackerID, attackerDefID, attackerTeamID)
      if (teamID and attackerTeamID)then
         isNotAlliedUnit = not AreTeamsAllied(teamID,attackerTeamID)
         if (unitID and attackerID and unitID ~= attackerID and (isNotAlliedUnit)) then
            playerDamageTaken[teamID]         = playerDamageTaken[teamID] + math.floor(damage)
            playerDamageDealt[attackerTeamID]   = playerDamageDealt[attackerTeamID] + math.floor(damage)
         end
      end
   end
   
   function gadget:UnitDestroyed(unitID, unitDefID, teamID, attackerID, attackerDefID, attackerTeamID)
      if (teamID and attackerTeamID)then
         isNotAlliedUnit = not AreTeamsAllied(teamID,attackerTeamID)
         
         if (unitID and attackerID and unitID ~= attackerID and (isNotAlliedUnit)) then
            table.insert(playerUnitKills, {unitDefID = 1})
            playerKills[attackerTeamID]   = playerKills[attackerTeamID]+1
            playerDeaths[teamID]      = playerDeaths[teamID]+1
            
            if (playerKills[attackerTeamID] > playerLeadKills) then
               playerLeadKills = playerKills[attackerTeamID]
               
               if (attackerTeamID ~= playerLeadID) then
                  playerLeadID = attackerTeamID
                  -- set top player ID
               end
            end
            
            playerScores[attackerTeamID] = playerScores[attackerTeamID] + 10
            
            if(UnitDefs[unitDefID].customParams )then
               pointValue = 0
               experienceValue = 0
               
               if(UnitDefs[unitDefID].customParams.costmaterials)then
                  pointValue = pointValue + (UnitDefs[unitDefID].customParams.costmaterials)*2
                  experienceValue = experienceValue + (UnitDefs[unitDefID].customParams.costmaterials)/2
               end
                              
               if(UnitDefs[unitDefID].customParams.costrefined)then
                  pointValue = pointValue + (UnitDefs[unitDefID].customParams.costrefined)*2
                  experienceValue = experienceValue + (UnitDefs[unitDefID].customParams.costrefined)/3
               end
                              
               if(UnitDefs[unitDefID].customParams.costexotic)then
                  pointValue = pointValue + (UnitDefs[unitDefID].customParams.costexotic)*50
                  experienceValue = experienceValue + (UnitDefs[unitDefID].customParams.costexotic)/2
               end
               
               math.floor(pointValue/1.5)
               playerScores[attackerTeamID] = playerScores[attackerTeamID] + pointValue
               playerExperience[attackerTeamID] = playerExperience[attackerTeamID] + experienceValue
               
               -- if we have exceded the experience required for the next rank
               -- bump our level
               --Spring.Echo(playerLevelRank[attackerTeamID]+1,
               --   levels[playerLevelRank[attackerTeamID]+1].xp,
               --   playerExperience[attackerTeamID])
               
               --avoid null errors
               if (playerLevelRank[attackerTeamID])then
                  local level = playerLevelRank[attackerTeamID]
                  level = tonumber(level)
                  --Spring.Echo("currentlevel:", level, levels[level].xp, playerExperience[attackerTeamID])
                  if (levels[level].xp <= playerExperience[attackerTeamID] ) then
                     -- we have reached a level up, have we
                     -- possibly gained enough xp to exceed the current level?

                     while (levels[level].xp <= playerExperience[attackerTeamID])do
                        level = level +1
                        --Spring.Echo(level, levels[level].xp, playerExperience[attackerTeamID])
                     end
                     
                     --Spring.Echo("new level:", level)
                     playerLevelRank[attackerTeamID] = level - 1
                     --Spring.Echo("Level up!", levels[playerLevelRank[attackerTeamID]+1].xp)
                  end
               end
            end
               -- Spring.Echo("PassScores",attackerTeamID,
                  -- "playerScores[team]", playerScores[attackerTeamID],
                  -- "playerExperience[team]", playerExperience[attackerTeamID],
                  -- "playerLevelRank[team]", playerLevelRank[attackerTeamID])
               SendToUnsynced("PassScores",attackerTeamID,
                  playerScores[attackerTeamID],
                  playerExperience[attackerTeamID],
                  playerLevelRank[attackerTeamID])
         end
      end
   end
   
   function gadget:Initialize()   
      GG.playerScores = playerScores
      _G.playerScores = playerScores
      
      GG.playerKills = playerKills
      _G.playerKills = playerKills
      
      GG.playerUnitKills = playerUnitKills
      _G.playerUnitKills = playerUnitKills
      
      GG.playerDeaths = playerDeaths
      _G.playerDeaths = playerDeaths
      
      GG.playerDamageTaken = playerDamageTaken
      _G.playerDamageTaken = playerDamageTaken
      
      GG.playerDamageDealt = playerDamageDealt
      _G.playerDamageDealt = playerDamageDealt
      
      GG.playerExperience = playerExperience
      _G.playerExperience = playerExperience

      GG.playerLevelRank = playerLevelRank
      _G.playerLevelRank = playerLevelRank

      for _,team in ipairs(GetTeamList()) do
         playerKills[team]      = 0
         playerUnitKills[team]   = {}
         playerDeaths[team]      = 0
         playerScores[team]      = 0
         
         playerDamageTaken[team]   = 0
         playerDamageDealt[team]   = 0
         
         playerExperience[team]   = 0
         playerLevelRank[team]   = startRank
      end
   end
   
   function gadget:RecvLuaMsg(msg, playerID)
      if msg:sub(1,12) == 'playerchange' then
         msg = tonumber(msg:sub(13))

         --Spring.Echo("PassScores",msg,
         --   playerScores[msg],
         --   playerExperience[msg],
         --   playerLevelRank[msg])
         SendToUnsynced("PassScores",msg,
            playerScores[msg],
            playerExperience[msg],
            playerLevelRank[msg])
      end
   end
   
   function gadget:GameFrame(gameFrame)
      if gameOver then return end   

      if gameFrame % 30 < 0.1 then
         for team, points in pairs (playerScores) do
            -- Spring.Echo("PassStats",team,
               -- "playerKills[team]", playerKills[team],
               -- "playerDeaths[team]", playerDeaths[team],
               -- "playerDamageTaken[team]", playerDamageTaken[team],
               -- "playerDamageDealt[team]", playerDamageDealt[team])
               
            -- SendToUnsynced("PassStats",team,
               -- playerKills[team],
               -- playerDeaths[team],
               -- playerDamageTaken[team],
               -- playerDamageDealt[team])   
         end
      end
   end   
   -- END SYNCED   
else
   -- BEGIN UNSYNCED

   local function POSToLuaUIScores(_,team, score, experience, rank)
      if (Script.LuaUI('PassScores')) then
         Script.LuaUI.PassScores(team, score, experience, rank)
      end
   end
   
   local function POSToLuaUIStats(_,team, kills, deaths, damageTaken, damageDealt)
      if (Script.LuaUI('PassStats')) then
         Script.LuaUI.PassStats(team, kills, deaths, damageTaken, damageDealt)
      end
   end
   
   function gadget:Initialize()
      gadgetHandler:AddSyncAction('PassStats',POSToLuaUIStats)
      gadgetHandler:AddSyncAction('PassScores',POSToLuaUIScores)      
   end
   -- END UNSYNCED      
end   

Code:
function widget:GetInfo()
   return {
      name         = "Chili score Bars",
      desc         = "",
      author         = "Smoth",
      date         = "2011",
      license          = "PD",
      layer          = 10,
      experimental   = false,
      enabled          = true
   }
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local Chili
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local levels       = VFS.Include("gamedata/ranks.lua")
local white_argb   = WG.colors["white_argb"]

local scoreBarTip = "\n" .. white_argb .. " Just your player score, no game value, just for fun :) "
local rankBarTip = "\n" .. white_argb .. " Experience to the next level"

local col_metal = {136/255,214/255,251/255,1}
local col_energy = {1,1,0,1}

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local scoreBar
local bar_score
local img_rank
local lbl_rank
local bar_rank

local RatioVal   = WG.RatioVal
local FontSize = WG.FontSize

local outputwind
options_section = 'Interface'

local updateMe

local next_update = 0

local phase      = 0
local restimer   = 0
local myRank   = 1

local function printbar_scoredata(self)
   Spring.Echo(scoreBarTip)
end   

local function printbar_rankdata(self)
   Spring.Echo(rankBarTip)
end   

function PassScores(team, score, experience, rank)

   if (team == WG.myTeamID) then
      --Spring.Echo(team, score, experience, rank, "PassScores")
      myScore = math.floor(score)
      experience = math.floor(experience)
      percentToNextLevel =  math.floor((experience/(levels[rank+1].xp))*100)
      bar_score:SetCaption(math.floor(myScore))
      
      bar_rank:SetCaption( experience .. "/" .. levels[rank+1].xp)
      bar_rank:SetValue(percentToNextLevel)
      --Spring.Echo("rank", myRank, rank)
      if (myRank ~= rank or updateMe == true) then
         myRank = rank
         --Spring.Echo(WG.myFaction, " Faction")
            if WG.myFaction == "zeon" then
               --Spring.Echo("bitmaps/ui/ranks/large/zeon/(" .. levels[rank].img .. ").png")
               img_rank.file = "bitmaps/ui/ranks/large/zeon/(" .. levels[rank].img .. ").png"
               img_rank:Invalidate()
            else
               --Spring.Echo("bitmaps/ui/ranks/large/federation/(" .. levels[rank].img .. ").png")
               img_rank.file = "bitmaps/ui/ranks/large/federation/(" .. levels[rank].img .. ").png"
               img_rank:Invalidate()
            end
         lbl_rank:SetCaption("Player Rank: " .. rank)
         lbl_rank:Invalidate()
         
         updateMe = false
      end
   end   
end

function widget:Update(s)
   if ( WG.uiElementRegistry["scorebar"] == true) then
      --Spring.Echo('playerchange' .. WG.myTeamID)
      Spring.SendLuaRulesMsg('playerchange' .. WG.myTeamID)
      
      bar_rank.color               = WG.rankColor
      scoreBar.color               = WG.mainColor
      bar_score.color               = WG.rankColor
      bar_score.backgroundColor      = WG.secondaryColor
      bar_rank.backgroundColor      = WG.secondaryColor
      
      scoreBar:Invalidate()
      bar_score:Invalidate()
      bar_rank:Invalidate()
      
      WG.uiElementRegistry["scorebar"] = false
      
      updateMe = true
   end
   
   if ( tonumber(Spring.GetGameSeconds()) >= 3600) then
      currenttime = (math.floor(Spring.GetGameSeconds()/3600) .. "." .. math.floor(Spring.GetGameSeconds()/60) .. "." .. math.floor(Spring.GetGameSeconds()%60) )
   elseif ( tonumber(Spring.GetGameSeconds()) >= 60) then
      currenttime = (math.floor(Spring.GetGameSeconds()/60) .. "." .. math.floor(Spring.GetGameSeconds()%60))
      else
      currenttime = (math.floor(Spring.GetGameSeconds()%60))      
   end
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


function widget:Initialize()
   widgetHandler:RegisterGlobal("PassScores", PassScores)
   WG.uiElementRegistry["scorebar"] = true
   
   Chili = WG.Chili
   
   if (not Chili) then
      widgetHandler:RemoveWidget()
      return
   end
   
   scoreBar   = Chili.Window:New{
      color   = {1,1,1,1},
      parent   = Chili.Screen0,
      name   = "Score Bar",
      right   = 20 * RatioVal,
      y      = 0,
      
      dockable      = true,
      width         = 10 * RatioVal,
      height         = 5.5 * RatioVal,
      draggable      = true,
      resizable      = true,
      color         = WG.mainColor,
      -- skinName   = "Gtechbar",
   }
   
   bar_score   = Chili.Progressbar:New{
      parent         = scoreBar,
      color         = WG.rankColor,
      backgroundColor   = WG.secondaryColor,
      
      height      = "35%",
      width      = "90%",
      x         = "5%",
      y         = "60%",
      fontsize   = FontSize,
      tooltip    = scoreBarTip,
      -- skinName   = "Gtechbar",
   }

   img_rank   = Chili.Image:New{
      parent   = scoreBar,
      file   = "",
      width   = "29%", 
      height   = "50%",
      x      = "5%",
      y      = "17%",
   }
   
   bar_rank   = Chili.Progressbar:New{
      parent         = scoreBar,
      color         = WG.rankColor,
      backgroundColor   = WG.secondaryColor,
      
      height      = "35%",
      width      = "62%",
      x         = "34%",
      y         = "25%",
      fontsize   = FontSize,
      tooltip    = rankBarTip,
      -- skinName   = "Gtechbar",
   }
   
   lbl_rank = Chili.Label:New{
      parent   = scoreBar,
      caption   = "Player Rank: 1",
      y      = "2%",
      left   = "10%",
      fontsize = FontSize,
   }
   
   butt_rank = Chili.Button:New{
      parent   = bar_rank,
      backgroundColor   = {1,1,1,0},
      x      = "2.5%",
      y      = "45%",
      height   ="70%",
      width   ="95%",
      caption = "",
      OnMouseUp = {printbar_rankdata}
   }
   
   butt_score = Chili.Button:New{
      parent   = bar_score,
      backgroundColor   = {1,1,1,0},
      x      = "2.5%",
      y      = "45%",
      height   ="70%",
      width   ="95%",
      caption = "",
      OnMouseUp = {printbar_scoredata}
   }

   
   bar_score:SetCaption(0)
   
   function bar_rank:HitTest(x,y) return self end
   function bar_score:HitTest(x,y) return self end
end


Sorry about the code being a mess but this is the simplest example I can give you.

Look specifically at PassScores


Top
 Offline Profile  
 
PostPosted: 16 Feb 2012, 04:32 

Joined: 10 Feb 2012, 23:20
Thank you!

Seeing this now I realize how close I was. My issue was that I never tried passing to Unsynced before sending to the Widget. I managed to come up with something funky using Spring.SendLuaUIMsg and a lot of string parsing, but I think this is a much cleaner solution (and requires less procsessing).

To summarize for anybody else checking the thread:

Gadget:
[*]Send function from Synced -> Unsynced in the same gadget
[*]Script.LuaUI.myFunc(values) to pass to widget

Code:
--Synced

local function SomeOtherFuction ()
   ...
   SendToUnsynced("PassScores",msg,
      playerScores[msg],
      playerExperience[msg],
      playerLevelRank[msg])
   ...
end

--Unsynced      

local function POSToLuaUIScores(_,team, score, experience, rank)
  if (Script.LuaUI('PassScores')) then
    Script.LuaUI.PassScores(team, score, experience, rank)
  end
end

function gadget:Initialize()
  gadgetHandler:AddSyncAction('PassScores',POSToLuaUIScores)     
end


Widget:
[*]Create a function to handle the inputs
[*]RegisterGlobal the incoming function

Code:
function widget:Initalize()
   widgetHandler:RegisterGlobal("PassScores", PassScores)
   ...
end   

function PassScores(team, score, experience, rank)
   if (team == WG.myTeamID) then 
      --Use values as desired
   end   
end


Top
 Offline Profile  
 
PostPosted: 16 Feb 2012, 05:02 
Content Developer
User avatar

Joined: 13 Jan 2005, 00:46
Location: ModalitÃ
no problem. I need to get off my ass and feed the wiki more. :P


Top
 Offline Profile  
 
PostPosted: 02 Jul 2012, 18:05 

Joined: 25 Jun 2012, 18:18
Nerris, your summary post was incredibly helpful to me. That should definitely go on the wiki somewhere. However, I've discovered that sending tables is slightly more complex. Hopefully someone will benefit from what took me days to figure out:

Since SendToUnsynced doesn't accept tables, you have to use _G and SYNCED as mentioned in this wiki article: Lua sync to unsync. Additionally, before sending SYNCED.SomeTable to the widget via Script.LuaUI.SomeFunction, it must be duplicated using spairs, as also shown in that wiki article (reason: viewtopic.php?f=23&t=25510&p=477787#p477787). Then, the duplicated table can be passed to Script.LuaUI.SomeFunction like any other argument.


Top
 Offline Profile  
 
PostPosted: 02 Jul 2012, 18:16 
Moderator

Joined: 05 Aug 2009, 19:42
Yes, I've used this post as well recently myself.
The problem with tables can possibly be done with a trick with savetable.lua (you can probably find it in the forums and many mods, but here it is).

So what I do is I pack my stuff in a table before sending it, and unpack it after, like:

str = table.show(myTable)
--send str

--recieve str
myTable = loadstring(str)()


Attachments:
savetable.lua [5.68 KiB]
Downloaded 107 times
Top
 Offline Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group

Site layout created by Roflcopter et al.