SaveUtils.lua -- Itemized Data Storage Across Mods

What you found is still very useful, though, as far as UI files are concerned. It also cuts down on the number of load calls to SaveUtils (only necessary when initializing; I've only got it in the Get functions) which decreases overhead.

So still, very nice. :goodjob:

Quick rewrite of a get function to properly initialize the value:
Code:
function getDarkAgeTurns(self)
	if (self.DarkAgeTurns == nil) then
		self.DarkAgeTurns = load( self, "DarkAgeTurns" ) or 0;
	end
	return self.DarkAgeTurns;
end
Player.GetDarkAgeTurns = getDarkAgeTurns;

Everywhere else you would have a load function, you just replace it with pPlayer:GetDarkAgeTurns(). :goodjob:
 
Ah. Unfortunate discovery.

Without forcing my file to load first via InGame.xml, TopPanel tries to call the new functions before they are defined, and causes an error. It partially recovers right after (the standard display works), but the mouseover functions are never loaded. Bad thing.

Could probably move the get/set functions into toppanel, and have it work that way, but I prefer to keep as much of my code isolated as possible. :lol: Plus, with the necessity of the load() call within the get() function, that hurts the modularity benefit that the function had in the first place.
 
Everywhere else you would have a load function, you just replace it with pPlayer:GetDarkAgeTurns(). :goodjob:

Using a mixture of both, you can really cut down the code. Do yourself a favour and get rid of the Gets and Sets!

Globals:
Code:
bNeedToLoadData = true;
bNeedToSaveData = false;
Player.ICSHappinessFromBuildings = Player.ICSHappinessFromBuildings or 0;
Player.ICSCheckHandicapHappy = Player.ICSCheckHandicapHappy or 0;
Player.ICSHappinessFromHandicap = Player.ICSHappinessFromHandicap or 0;
Player.ICSBureaucracyUnhappiness = Player.ICSBureaucracyUnhappiness or 0;

In your begin turn event:
Code:
		local pPlayer = Players[Game.GetActivePlayer()];
		if( bNeedToLoadData ) then
			pPlayer.ICSHappinessFromBuildings = load( pPlayer, "ICSHappinessFromBuildings" );
			pPlayer.ICSCheckHandicapHappy = load( pPlayer, "ICSCheckHandicapHappy" );
			pPlayer.ICSHappinessFromHandicap = load( pPlayer, "ICSHappinessFromHandicap" );
			pPlayer.ICSBureaucracyUnhappiness = load( pPlayer, "ICSBureaucracyUnhappiness" );
			bNeedToLoadData = false;
		end

In your code if you change one of the values change the to save flag to true.
Code:
		if( count ~= pPlayer.ICSHappinessFromBuildings ) then
			pPlayer.ICSHappinessFromBuildings = count;
			bNeedToSaveData = true;
		end

Then in your end turn event:
Code:
		local pPlayer = Players[Game.GetActivePlayer()];
		if( bNeedToSaveData ) then
			save( pPlayer, "ICSHappinessFromBuildings", pPlayer.ICSHappinessFromBuildings );
			save( pPlayer, "ICSCheckHandicapHappy", pPlayer.ICSCheckHandicapHappy );
			save( pPlayer, "ICSHappinessFromHandicap", pPlayer.ICSHappinessFromHandicap );
			save( pPlayer, "ICSBureaucracyUnhappiness", pPlayer.ICSBureaucracyUnhappiness );
			bNeedToSaveData = false;
		end

Much cleaner, and not having to rely on Gets and Sets which can get messy. :)
 
Ah. Unfortunate discovery.

Without forcing my file to load first via InGame.xml, TopPanel tries to call the new functions before they are defined, and causes an error. It partially recovers right after (the standard display works), but the mouseover functions are never loaded. Bad thing.

Could probably move the get/set functions into toppanel, and have it work that way, but I prefer to keep as much of my code isolated as possible. :lol: Plus, with the necessity of the load() call within the get() function, that hurts the modularity benefit that the function had in the first place.

How are you loading your file? This works for me if I define my file as an InGameUIAddin
 
How are you loading your file? This works for me if I define my file as an InGameUIAddin

Exactly that way. :lol:

I can tell toppanel to include my files, which eliminates that particular issue, but then on that initial load I return to the cache issue and have to include the modname and kill the cache.
 
Your save/load method gets a bit convoluted once you expand it to cover all players rather than just the human. Ends up either using an array, or not saving considerably on save/load calls. ;)

Notice I used active player in turn start and end? No need to worry about the other players. ;)

Specifically: Events.ActivePlayerTurnStart
 
Notice I used active player in turn start and end? No need to worry about the other players. ;)

Specifically: Events.ActivePlayerTurnStart

I know. That does not cover any AI players, unless I have missed something very large.

And I highly doubt I missed anything, as while testing I had print functions that should have printed for every single player, regardless of if they had positive happiness or negative.

I would prefer not to have a modcomp add mechanics that only affect the player. ;)
 
Exactly that way. :lol:

I can tell toppanel to include my files, which eliminates that particular issue, but then on that initial load I return to the cache issue and have to include the modname and kill the cache.

Hmm strange, I have a TopPanel edit for my city maintenance script, too, and my custom script is executed first, correctly setting up the player variables.

Additionally, I just checked the game restart and reload and it seems to work for me :crazyeye:

I wonder what we're doing different seeing that we get totally different results. If you send me your email address via PM I can maybe send you a working copy of my mod so you can test it?
 
Email is valkrionn@yahoo.com, should be on my profile as well. I don't mind people knowing it. ;)

Ok, dispatched. I don't usually check profiles because most people don't have their mail exposed due to spambot action :)

By the way, could you help me out with a bit of SQL code? I want to try to change the type of the artist CulturePerTurn column from integer to double. What would I have to do? The table is Specialists. I tried

ALTER TABLE Specialists
DROP COLUMN CulturePerTurn;
ADD CulturePerTurn double default 0;

and

ALTER TABLE Specialists
MODIFY COLUMN CulturePerTurn double;
 
I would think that both of those would work, assuming you're adding the file to the database.

I'd have to play around with it in sqlite to be sure, though.

One thing I'd recommend: Try making the change, and then using a print function to actually check it (set a specialist to provide decimal culture, then print it's culture value).
 
I know. That does not cover any AI players, unless I have missed something very large.

And I highly doubt I missed anything, as while testing I had print functions that should have printed for every single player, regardless of if they had positive happiness or negative.

I would prefer not to have a modcomp add mechanics that only affect the player. ;)

I've got it in UpdateData() of TopPanel.lua and that one IS called for every player. I had a "Got here" in my code and it runs for every player.
 
Hmm strange, I have a TopPanel edit for my city maintenance script, too, and my custom script is executed first, correctly setting up the player variables.

Additionally, I just checked the game restart and reload and it seems to work for me :crazyeye:

I wonder what we're doing different seeing that we get totally different results. If you send me your email address via PM I can maybe send you a working copy of my mod so you can test it?

I'd be interested in seeing that too, I'm getting
Code:
Runtime Error: [string "C:\Users\**\Documents\My Games\Sid Meier..."]:428: attempt to index global 'cacheState' (a nil value)
 Runtime Error: Error loading Assets/UI/InGame/TopPanel.lua.

thesdale@gmail.com
 
Oh god yeah, still very useful and a great find! Don't want to imply otherwise. :D

Just in congratulating you didn't want to risk undermining Whys' work which obviously he's put a massive amount of time into is all. :D

Thanks lemmy. :)

Recommendations are more than welcome in this thread, and hacks are great, but they shouldn't be confused with consistently reliable code.

So is Player the only thing you can attach data to like that, or are there others?
 
Ok, I do see that it's not saved now, it was just my code screwing me over and making me think it did.

Thanks lemmy. :)

Recommendations are more than welcome in this thread, and hacks are great, but they shouldn't be confused with consistently reliable code.

So is Player the only thing you can attach data to like that, or are there others?

I wouldn't say this is really a hack, I'm just modifying a class from the Lua side instead of the C++ side, so I'm well in the realm of using lua like it's meant to be used. The only thing that doesn't work, then, is to store the data, but for this we have your wonderful SaveUtils

I would expect you can do this with any and every Lua table in the game. If the table is kept in memory and not constantly re-generated from C++, that is. So it should work with any game object like City, Plot, Team, and so on. I am personally notorious to do it with string in order to add a string:split function, so it works for the library, too, but is discarded when the VM is ended.

Edit: Dale your run-time error sounds like you're trying to use SaveUtils somewhere and the cacheState isn't set in the context. If you load as an InGameUIAddin, TopPanel will not share the global namespace for the cacheState so you need to include SaveUtils in TopPanel
 
Top Bottom