Jump to content

Display data wrong/crash on World with caves


Recommended Posts

Hello there,

I converted a DS mod to DST mod. It worked well with Single Play and World without Caves.

But in World with Caves, something go wrong when I display my data.

Sometimes, it crashes with 'nil'. Sometimes, it shows only 0 level & 0 exp. The actually data is very different when I used my commands to test.

local G = GLOBAL

local function GetPlayer()
	if IsDST() then
		return GLOBAL.ThePlayer
	else
		return GLOBAL.GetPlayer()
	end
end

local INFO_KEY = GetModConfigData("Show Info")

--Show player level info
local function GetInfo()
	if not G.IsPaused() then
		if IsDST() then
			GetPlayer().components.talker:Say(
				string.format(
					"Level: %d\nXP: %d/%d\nSpeed bonus: +%.4f%%",
					GetPlayer().components.leveluplan.levelLan,
					math.floor(GetPlayer().components.leveluplan.expLan),
					GetPlayer().components.leveluplan:XPneed(),
					((2.2 - 1.003 ^ -GetPlayer().components.leveluplan.levelLan) / 1.2 - 1) * 100
				)
			)
		else
			GetPlayer().components.talker:Say(
				string.format(
					"Level: %d\nXP: %d/%d\n%.4f speed",
					GetPlayer().components.leveluplan.levelLan,
					math.floor(GetPlayer().components.leveluplan.expLan),
					GetPlayer().components.leveluplan:XPneed(),
					GetPlayer().components.leveluplan.speedupLan
				)
			)
		end
	end
end

G.TheInput:AddKeyDownHandler(INFO_KEY, GetInfo)

 

Edited by Magic_Pro
Make more clear
Link to comment
Share on other sites

In DST, clients and servers are separated. Clients don't have most data calculated by the server because they don't need it.
So most components like leveluplan, class variables are just not existed. The only exception is when you're the host of the server hosted through the game(not dedicated) without a cave. In this case, the server and the client are the same.
That is - you have to change the code from the basics. If this code is not the whole features of the mod, you need to work on re-coding about those.

Read Differences chapter more carefully. At least if you want to understand this issue, 
it is required to understand what replica, RPC, netvars is. 
Please read the thread before you read below.


Let's look at the code from the perspective of problem-solving.
As I mentioned above, the client doesn't have information about those

GetPlayer().components.leveluplan.levelLan,
math.floor(GetPlayer().components.leveluplan.expLan),
GetPlayer().components.leveluplan:XPneed(),
((2.2 - 1.003 ^ -GetPlayer().components.leveluplan.levelLan) / 1.2 - 1) * 100

because component leveluplan may not exist in the client.
But what can we do? Adding the component in the client too? No.
We just need to run it in the server. Because the server has the info. And you can do it by using RPC.
Let's make a code sending RPC to the server.
The server receives the RPC, and execute the function that let the sender(the player prefab) say the info.

The first thing to do is to change AddKeyDownHandler().
A client raises KeyDown Event. So the client will send RPC.

G.TheInput:AddKeyDownHandler(INFO_KEY, function()
  if G.TheFrontEnd:GetActiveScreen() ~= nil and G.TheFrontEnd:GetActiveScreen().name == "HUD" then
    G.SendModRPCToServer(MOD_RPC["modprettyname"]["getinfo"], ThePlayer) 
  end
end)

You can freely change MOD_RPC's key. Just ensure "modprettyname" part distinguishable compared to other mods.
So if you press the key, the client says to the server: "Execute function in MODRPC.modprettyname.getinfo"
And... I won't use GetPlayer() because it will only call in DST code part.
Oh and IsPaused() is not used in DST. Instead, if G.TheFrontEnd:GetActiveScreen()~ part will prevent further sequences when any screen is activated.

Next is to add an RPC handler. If the server receives an RPC, it will execute the function in matching key(modprettyname.getinfo in this case) in MOD_RPC. Adding the function to MOD_RPC is this.

AddModRPCHandler("modprettyname", "getinfo", GetInfo)

You will notice that the key should be corresponding. Rename it correctly.
After the server received the RPC, it will call GetInfo() in server-side. The server does have the information.
However, the server doesn't know who  GetPlayer(ThePlayer) is.  So don't use it in GetInfo(). 
Instead, use a parameter passed by the RPC which is the sender's player entity.

..."modprettyname"]["getinfo"], ThePlayer) 

That parameter is actually ThePlayer, the argument of SendModRPCToServer.
Since this ThePlayer was sent by the client, the server can distinguish which player is to start function.

local function GetInfo(inst)	
  inst.components.talker:Say(
    string.format(
      "Level: %d\nXP: %d/%d\n%.4f speed",
      inst.components.leveluplan.levelLan,
      math.floor(inst.components.leveluplan.expLan),
      inst.components.leveluplan:XPneed(),
      inst.components.leveluplan.speedupLan
    )
  )
end

 

That will do it. Recode it as you want. Take a look at my character mod's code as well.
I've already made the feature similar to yours. 

Edited by YakumoYukari
Link to comment
Share on other sites

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
 Share

×
  • Create New...