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?
Send table from Synced Gadget -> Widget
Moderator: Moderators
Re: Send table from Synced Gadget -> Widget
Code: Select all
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: Select all
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
Look specifically at PassScores
Re: Send table from Synced Gadget -> Widget
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
Widget:
[*]Create a function to handle the inputs
[*]RegisterGlobal the incoming function
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: Select all
--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
[*]Create a function to handle the inputs
[*]RegisterGlobal the incoming function
Code: Select all
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
Re: Send table from Synced Gadget -> Widget
no problem. I need to get off my ass and feed the wiki more. 

Re: Send table from Synced Gadget -> Widget
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: http://springrts.com/phpbb/viewtopic.ph ... 87#p477787). Then, the duplicated table can be passed to Script.LuaUI.SomeFunction like any other argument.
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: http://springrts.com/phpbb/viewtopic.ph ... 87#p477787). Then, the duplicated table can be passed to Script.LuaUI.SomeFunction like any other argument.
Re: Send table from Synced Gadget -> Widget
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)()
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 118 times