Jump to content

Recommended Posts

 

Hi, guys, I want to add a text widgets to show the exp of a character made by another author.

Here is the define of the character's exp and expmax

local common_postinit = function(inst)
 	......
    inst:AddTag("sora")
    inst.soraexp = net_int(inst.GUID, "sora_exp", "soraexpdirty")
    inst.soraexpmax = net_int(inst.GUID, "sora_expmax", "soraexpdirty")
  	.......
end

 

Here is my code

scripts/widgets/sora_exp_title.lua

local Widget = require "widgets/widget"
local Text = require "widgets/text"

local SoraExpTitle = Class(Widget, function(self, owner)
    Widget._ctor(self, "SoraExpTitle")
    self.soraexptitle = self:AddChild(Text(BODYTEXTFONT, 30))

    owner:ListenForEvent("soraexpdirty", function(owner, data) 
        self.exp = owner.soraexp:value()
        self.maxexp = owner.soraexpmax:value()
    end)

    self:StartUpdating()
end)

function SoraExpTitle:OnUpdate(dt)
    local str = self.exp.." / "..self.maxexp
    self.soraexptitle:SetString(str) 
end

return SoraExpTitle

modmain.lua

local soraexptitle = GLOBAL.require("widgets/sora_exp_title")

AddClassPostConstruct("widgets/controls", function(self)
    if not self.owner:HasTag("sora") then
        return
    end

    self.title = self:AddChild(soraexptitle(self.owner))
    self.title:SetHAnchor(0)
    self.title:SetVAnchor(1)
    self.title:SetPosition(70,-50,0)
end) 

 

The question is when i first enter the game, everything is ok, but when game reload(whether quit or not quit the game), the widgets show wrong value of the exp.

It seems that there is a problem with the data synchronization of the network variables. 

Here are some of my findings

1. I make a healer prefab, when i use it, it always works well

local function showExp(inst, target)
    if target ~= nil then
        if target:HasTag("sora") then
            TheNet:Say(target.soraexp:value() .. ' / ' .. target.soraexpmax:value())
        end
    end
end
---------------------------------------
	······
    inst:AddComponent("healer")
    inst.components.healer.health = 0
    inst.components.healer.Heal = showExp
	·······
return Prefab("sora_exp_show", fn, assets, prefabs)

(It seems that true value is normal on the server, but the client is only valid when you first enter the game)

2. Another place store  experience

TheWorld.components.soraexpsave.exps[userid]

It's not a netvar type, i don't know how to listen to the change of this table and get its value in widgets.

 

Some code about the character's exp

-- store/restore the exp when game save/reload 


local soraexpsave = Class(function(self, inst)
    self.inst = inst
    self.exps={}
end)


function soraexpsave:SetExp(userid,setexp)      
    self.exps[userid] = setexp
end
function soraexpsave:GetExp(userid)      
    return userid and self.exps[userid] and math.max(0,self.exps[userid]-1000) or -1
end


function soraexpsave:OnSave() 
	return  {exps=self.exps} or { a =1}
end

function soraexpsave:OnLoad(data)       
	if data then
        self.exps = data.exps or {}
	end
end

return soraexpsave
local function OnSoraSpawn(inst)
    local first = true
    if TheWorld.components.soraexpsave then
        local saveexp = TheWorld.components.soraexpsave:GetExp(inst.userid)
        first = saveexp == -1
        if saveexp > 0 then inst:GetExp(saveexp) end
    end
end

set exp

local function GetExp(inst, num, code, dmaxexp, once)
    inst.soraexp:set(math.max(0, inst.soraexp:value() + num))
    if inst.soralevel:value() < 30 and inst.soraexp:value() >=
        expfornextlev(inst.soralevel:value()) or num <= 0 then
        applyupgrades(inst, true)
    end
    inst.soraexpget = inst.soraexpget + num
    if inst.soraexpget > 1000 then
        inst.soraexpget = 0
        applyupgrades(inst, true)
    end
    TheWorld.components.soraexpsave:SetExp(inst.userid, inst.soraexp:value())
end

 

Is there any way to solving the above problem? Please help, thanks~

 

 

If I remember correctly, this happens because you have the ListenForEvent in the construction of the widget with owner as the instance. I think somehow this instance of the owner can change so that it isn't able to listen to events.

I think you can fix this by adding the ListenForEvent in the AddClassPostConstruct:

Spoiler

local soraexptitle = GLOBAL.require("widgets/sora_exp_title")

AddClassPostConstruct("widgets/controls", function(self)
    if not self.owner:HasTag("sora") then
        return
    end

    self.title = self:AddChild(soraexptitle(self.owner))
    self.title:SetHAnchor(0)
    self.title:SetVAnchor(1)
    self.title:SetPosition(70,-50,0)
    
     self.owner:ListenForEvent("soraexpdirty", function(owner, data) 
        self.exp = owner.soraexp:value()
        self.maxexp = owner.soraexpmax:value()
    end)
end) 

 

 

1 hour ago, Monti18 said:

If I remember correctly, this happens because you have the ListenForEvent in the construction of the widget with owner as the instance. I think somehow this instance of the owner can change so that it isn't able to listen to events.

I think you can fix this by adding the ListenForEvent in the AddClassPostConstruct:

  Hide contents


local soraexptitle = GLOBAL.require("widgets/sora_exp_title")

AddClassPostConstruct("widgets/controls", function(self)
    if not self.owner:HasTag("sora") then
        return
    end

    self.title = self:AddChild(soraexptitle(self.owner))
    self.title:SetHAnchor(0)
    self.title:SetVAnchor(1)
    self.title:SetPosition(70,-50,0)
    
     self.owner:ListenForEvent("soraexpdirty", function(owner, data) 
        self.exp = owner.soraexp:value()
        self.maxexp = owner.soraexpmax:value()
    end)
end) 

 

 

thanks for your answer , I tried,  It shows up correctly when I enter the game and do nothing, but when my exp changes(like do work pick, character will increase 2 exp), the exp shows up incorrectly again. It's really weird.

my code

local soraexptitle = GLOBAL.require("widgets/sora_exp_title")
AddClassPostConstruct("widgets/controls", function(self)
    if not self.owner:HasTag("sora") then
      return
    end

    self.title = self:AddChild(soraexptitle(self.owner))
    self.title:SetHAnchor(0)
    self.title:SetVAnchor(1)
    self.title:SetPosition(70,-50,0)

    self.owner:ListenForEvent("soraexpdirty", function(owner,data) owner.exp = owner.soraexp:value() owner.maxexp = owner.soraexpmax:value() end) 
  end) 

 

local Widget = require "widgets/widget"
local Text = require "widgets/text"

local SoraExpTitle = Class(Widget, function(self, owner)
    Widget._ctor(self, "SoraExpTitle")
    self.soraexptitle = self:AddChild(Text(BODYTEXTFONT, 30))
    self.owner = owner
    self:StartUpdating()
end)

function SoraExpTitle:OnUpdate(dt)
    self.owner.exp = self.owner.exp and self.owner.exp or '-'
    self.owner.maxexp = self.owner.maxexp and self.owner.maxexp or '-'
    local str = self.owner.exp.." / "..self.owner.maxexp
    self.soraexptitle:SetString(str)
    return 
end


return SoraExpTitle

Is it possible for the author to add some monitoring? I checked all the code related to exp, but I found no sign of doing so.

Edited by ccpalyer

Try replacing your widget with this:

Spoiler

local Widget = require "widgets/widget"
local Text = require "widgets/text"

local SoraExpTitle = Class(Widget, function(self, owner)
    Widget._ctor(self, "SoraExpTitle")
    self.soraexptitle = self:AddChild(Text(BODYTEXTFONT, 30))

    self.inst:ListenForEvent("soraexpdirty", function(owner, data) 
        self.exp = owner.soraexp:value()
        self.maxexp = owner.soraexpmax:value()
    end,owner)

    self:StartUpdating()
end)

function SoraExpTitle:OnUpdate(dt)
    local str = self.exp.." / "..self.maxexp
    self.soraexptitle:SetString(str) 
end

 

The ListenForEvent is written with the owner added at the end, which makes a difference as to how it is called.

On 1/14/2022 at 9:09 PM, Monti18 said:

Try replacing your widget with this:

  Reveal hidden contents


local Widget = require "widgets/widget"
local Text = require "widgets/text"

local SoraExpTitle = Class(Widget, function(self, owner)
    Widget._ctor(self, "SoraExpTitle")
    self.soraexptitle = self:AddChild(Text(BODYTEXTFONT, 30))

    self.inst:ListenForEvent("soraexpdirty", function(owner, data) 
        self.exp = owner.soraexp:value()
        self.maxexp = owner.soraexpmax:value()
    end,owner)

    self:StartUpdating()
end)

function SoraExpTitle:OnUpdate(dt)
    local str = self.exp.." / "..self.maxexp
    self.soraexptitle:SetString(str) 
end

 

The ListenForEvent is written with the owner added at the end, which makes a difference as to how it is called.

It doesn't work either. T_T, when the game doesn't include the cave, everything works fine.

15 hours ago, ccpalyer said:

It doesn't work either. T_T, when the game doesn't include the cave, everything works fine.

That's because the game doesn't run as a client connected to a server when you host a game without caves, you ARE the server, meaning any server data is directly shown to you,since you, well, are the server.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...