How do I prevent my View from trying to load until a game is loaded?

I’m experiencing a somewhat more nuanced problem right now, but I think this is general good modding information.

Specifically in my case, on initialization my view is calling a Lua call handler which requests a datastore from my service. If that datastore doesn’t exist yet, it creates it and gives it data based on saved variables. However, apparently one of the functions in my Lua service is nil at the time that this is initially called when I launch the game, resulting in an engine error! Other functions aren’t nil, and when I hop in the Lua console and check the function in question, it’s not nil.

That doesn’t sound Call handlers are require()d when you call a function, so they are guaranteed to be fully evaluated. If you’re using some other service that isn’t ready yet, you should listen to the appropriate events on the Lua side and resolve the response asynchronously.

Hmm… is there something I can look at as a guide for waiting until a service is loaded?

Services are loaded in order, and stonehearth ones will load first. Each service has its own initialization logic, but most initialize synchronously. Can you show the specific issue?

I have the following server-level call handler:

function ObligationTrackerCallHandler:get_obligation_monitor(session, response)
	local obligation_monitor = obligation_tracker.obligation_tracker:get_obligation_monitor(session.player_id)
	response:resolve({ obligation_monitor = obligation_monitor })
end

When my Ember view is created, it calls that get_obligation_monitor function. These are some functions in my service:

function ObligationTrackerService:_get_player_sv(player_id)
	if not self._sv.player_data[player_id] then
		local data = {}
		data.timers = {
			consumables = {}, -- { buff_uri = { time_started, duration } }
			trading_stalls = {} -- { specific_uri = { time_started, duration } }
		}
		data.auto_use = {}

		self._sv.player_data[player_id] = data
	end

	return self._sv.player_data[player_id]
end

function ObligationTrackerService:get_obligation_monitor(player_id)
	if not self.obligation_monitor[player_id] then
		local data = radiant.create_datastore()
		self.obligation_monitor[player_id] = data
		self._set_obligation_monitor_data(player_id)
	end

	return self.obligation_monitor[player_id]
end

function ObligationTrackerService:_set_obligation_monitor_data(player_id, player_data)
	if not self._get_player_sv then
		radiant.log.write('obligationtracker', 0, 'Why is self._get_player_sv nil?!?')
	end

	if not player_data then
		player_data = self:_get_player_sv(player_id)
	end
	
	-- first prune defunct timers from the table
	self:_prune_defunct_timers(player_data)
	self:get_obligation_monitor(player_id):set_data({timers = player_data.timers, auto_use = player_data.auto_use})
	self.__saved_variables:mark_changed()
end

When the call handler is run, that radiant.log.write call is made, meaning (as far as I can tell) that at the time of the calling, the service is only partially initialized. Which is odd, because my server init script is normal, and obligation_tracker['obligation_tracker'] is not getting set until after it’s created and initialized, just like all other services.

That is unexpected. What do you get in the log if you print(self) at the start of _set_obligation_monitor_data()?

I figured it out. >< Notice anything wrong with this call?

self._set_obligation_monitor_data(player_id)

Yeah, I used . instead of :, so self wasn’t defined (or was defined as the player_id string) within the scope of that call of _set_obligation_monitor_data. Sorry to bother you about something so silly.