Spring's "economy", GET/SET MAX_SPEED

Spring's "economy", GET/SET MAX_SPEED

Discuss the source code and development of Spring Engine in general from a technical point of view. Patches go here too.

Moderator: Moderators

User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Spring's "economy", GET/SET MAX_SPEED

Post by Argh »

Hey devs... I wrote up an experimental script that changes the MAX_SPEED of a unit- shutting down movement if there isn't any Energy available.

It works, on the BOS side. The problem is... Spring doesn't seem to work right, and it has to do with the economy handler.

I've always had some questions, in the back of my mind, about the economy handler. NanoBlobs would work veeeeeeery differently in OTA- the wild ups and downs of the E/M "economy" would probably make it crash, for one. But even if it didn't, units would stop/start/stop on a regular basis, as the economy went empty during early game. In Spring, I've never had that problem, which has always seemed weird. At first, I used to have M/E costs for firing weapons, but that just didn't cause the stark effects I expected- instead, everything somehow magically slowed down proportionally, but never STOPPED.


My problem here is very basic: the economy never seems to go truly empty. It acts like it does- under veeeeeery specific circumstances. If you have a weapon that costs 10000 E to fire, then it won't fire until you hit 10000 E. However, I have yet to see one of my factories ever stop building entirely, so long as my economy had positive income- nevermind if that income was less than outgo and I have no reserves. I am sure this has been observed by serious players for ages, and probably beaten to death, but now that I'm trying to harness it beyond simple statistical stuff, it's very irksome, especially as there doesn't seem to be a way to turn it off.


Moving on, to my specific beef:

I wrote up a modified Archer script as a tester, and it has the following lines in the BOS:

Code: Select all

Activate()
{
	signal SIG_ACTIVATE;
	SET MAX_SPEED to [0.9375];
}

Deactivate()
{
	signal SIG_ACTIVATE;
	set-signal-mask SIG_ACTIVATE;
	SET MAX_SPEED to [0];
	moving=FALSE;
	set-signal-mask 0;	
}
Since Activate and Deactivate can shut something down if the economy goes into stall, and are what Spring is checking against... as you can see, this should shut the unit's movement down if there aren't any resources available.

I tried it out... and it didn't work. At all. I .gave myself dozens of Demons, to drain my economy so dry that I should never, ever, EVER have any Energy or Metal available... and yet, this thing still walked around as if nothing was wrong.

Soooo... I made it OnOffAble. And tested. And guess what? Every once in awhile, the code works just fine before suddenly getting interrupted.

Final test? Took out the EnergyUse/EnergyMake lines, to remove that condition. Guess what? Now it works- for less than a second.

So... there appear to be two things that are borked here:

1. After observing my M/E economy with dozens of Demons... something is horribly, horribly wrong. Dozens of Demons should equal instant economic stall, forever, period- we're talking negatives in the tens of thousands here. This is not what happens.

Instead, I can watch the full value of the Lord (200E, 200M) being put into the Economy, and it takes about a second for it to disappear down to zero. What's up with that? Why isn't the current cost of my economy being subtracted from my current gain before allowing for building new units? I mean... so far as I can tell, it's impossible to really stall. Is there any way to shut this off, mod-side, so that I can inflict proper stalling behavior on NanoBlobs? I want my units to stop moving when I tell them to- including when they don't have enough Energy to sustain themselves.

The main thing that irks me is that your Economy should always hit (and stay at) zero if your demand outstrips supply. What is causing this to not happen? Don't tell me it's some magical AI trick that's "autobalancing" the books- because if that's the answer, my answer to that is that it's obviously committing fraud somewhere, and we'd better make sure it isn't investing our money in shares of its stock ;) IRL, you cannot spend more than you actually have. In Spring, you can apparently spend forever, without consequences. After conducting experiments where my M/E economy was zero - SomeHugeNumbers... my script, above, only intermittantly DeActivated the unit- indicating that there is something seeeeeeriously wrong here with the way that Spring calculates income over time. If my Lord is dead, and I have 200 Demons, and I have a script like the one above... that Archer had better not move ;)

2. GET/SET MAX_SPEED doesn't seem to work for more than a half-second or so- I'm assuming that's a SlowUpdate. What's up with that? What's making this so hard to fix? I'm not saying you guys haven't been trying- I know that several of you have looked at this issue. But it's clearly still borked. Is there anything I could do that would be remotely helpful? I was planning to use this feature in the next version of NanoBlobs, since it didn't make the cut for 0.63, but it's not working right now, irregardless of the problem listed above.
Last edited by Argh on 07 Nov 2006, 13:41, edited 2 times in total.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

For those of you who don't want to read the entire, blog-like entry... lemme put it another way: why can I have an income of hundreds, an outgo of thousands, and not end up in massive debt, which must be repaid before I can do anything else? It works like that IRL, and it should darn well work that way in Spring, or it makes a lot've economic models ... kind've impossible :?
User avatar
yuritch
Spring 1944 Developer
Posts: 1018
Joined: 11 Oct 2005, 07:18

Post by yuritch »

The Spring economy is inherited from OTA AFAIK. Most units there used to have EnergyUse>0, yet they could still move if no energy was in storage. Only weapon fire was impossible without enough stored E/M.
Construction will work even if you have a +1/-100 situation (suppose the -100 is made up of 5 factories using an avg. of 20 resource/second each), just everything will be built at 1/100 the speed and what small income there is will be distributed between all the users, probably proportionally to each user's demand (so if one of the factories demands 40, it will get 0.4, if the other demands only 10, it will get 0.1 out of total). So, as long as there is any income at all, all factories will work (but probably very slowly), no matter how high is resource demand. The construction should only completely stop if there is a +0/-something situation and no stored resource available.
As for debt: it works for money, it doesn't work for stored energy or metals. You cannot have -100 tons of metal stored (or -10 A*h of electricity), your equipment will just stop at 0 (it cannot produce negative amount of units or fire -1 weapon shot).
What is needed engine-side is probably an unit-definable minimum stored resource amount. If the resource goes below that, the unit just stops receiving any resources from the distribution system and enters a permanent Off state (until resource situation improves). Inability to move if there is not enough energy should be engine side, too.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

The spring economy has actually changed from the OTA econoym in such a way it's actually removed one of the godlen rules fo gameplay, never stall, instead there's a growing league fo users who insist it si good to stall ebcaus eit shows you're usign all your resources, ddespite there still ebign arguements against the stall issue.

This issue has also meant none of the AIs are able to use an effective antistall algorithm because they arent able to accurately predict the flow of resources anymore.

In spring if you say add 11+ per second, what it actually means is add 11/32 every frame, which means you're not even getting 11 per second, you're getting 11*(32/30). It also means rather than one lump sum like in OTA being added every tick, it's instead being spread across and continuosly being added, which is one of the major causes of the current system.

Old style OTA tick resources would be very easy to switch to, it just means instead of adding energymake*(32/30) every frame, you're adding energymake every slowUpdate().

The current system also gives the user a slight overdraft since if you have 5 energy stored and it negates 6 energy you have -1, which is then reset to zero.
User avatar
rattle
Damned Developer
Posts: 8278
Joined: 01 Jun 2006, 13:15

Post by rattle »

Are you sure using the [] multiplier is right? Unless you changed it to 65k in scriptor...
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Guys, my point is simple:

When [fixed expenses > (available income + reserves)]
{
NothingInvolvingSpendingShouldBePossible.
}

That is not what happens. And I know why now. It's because while Energy and Metal are being added every tick, and taken out every tick by shooting/building... your fixed expenses are being taken out every SlowUpdate, and values lower than zero (i.e., negative balances) are being thrown out and replaced with zeros. Which is bad.

@Rattle, no, I'm sure that value is "wrong"- when the Archer actually got the command, it sped up like a shot- for half a second :P
User avatar
Lindir The Green
Posts: 815
Joined: 04 May 2005, 15:09

Post by Lindir The Green »

AF wrote:The spring economy has actually changed from the OTA econoym in such a way it's actually removed one of the godlen rules fo gameplay, never stall, instead there's a growing league fo users who insist it si good to stall ebcaus eit shows you're usign all your resources, ddespite there still ebign arguements against the stall issue.
All the OTA strat guides (that I read) said that you should always m-stall and never max out anything. They did however think that e-stalling was bad. [edit]Actually, I think I read one that said that e-stalling was really good, as long as its from metal makers. Not quite sure about that though.[/edit]

But yes I am all for fixing Spring so that stuff can't do stuff if it requires a resource to do it and that resource is stalling.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

More importantly, I have discovered that fixed expenses (i.e., things that the user or the engine don't control the spending of, like buildings that eat X amount of Energy per second) will never, EVER take your economy below zero!

Every tick, this is what should happen:

(Income - Fixed Expenses) + Reserves = Available Resources

Available Resources Now - Optional Expenses = Available Resources

If Available Resources < 0, then you should not be able to spend on optional expenses.

Lastly, if your income is a net negative, it should BE a net negative. Spring's current code wipes all your "debt" away every SlowUpdate, instead of halting spending or causing you to go further and further in debt. This is bad.
User avatar
Fanger
Expand & Exterminate Developer
Posts: 1509
Joined: 22 Nov 2005, 22:58

Post by Fanger »

It has to do with what AF said Argh, trust me hes right, I looked into this a long time ago, because I wanted to set up EE so it was very close to Earth 2150 which had the mechanic of buildings requiring energy to function and especially higher level defensive structures. I tried to implement a system for the defenses whereby they used energy to fire, and just sitting, but no matter how many I had or how little energy income I had all it did was just slow down their fire rate, not prevent them from firing period. The resources are wonky, the only way to simulate complete shutdown is to use negative storage, that is the only way currently to cause buildings to stop construction at all, as once they have 0 total reserves to draw from they cant draw anything and thus cease to function. However the problem with negative storage is that spring was hard coded to require at least 1 existing metal and energy to START construction, even if said resources are not required to build the actual unit they must still be there to START the construction. I hopped that they would remove this silly hardcode so that units could be built utilizing only one resource and negative storage could be added in, but I have yet to test and see if this is the case.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Fang, AF's last sentence is what I'm getting at:
The current system also gives the user a slight overdraft since if you have 5 energy stored and it negates 6 energy you have -1, which is then reset to zero.

It's not a "slight overdraft". It's an infinite one. Start up NanoBlobs, .give yourself dozens of Demons, and watch as your Energy/Metal rises above zero over and over again, even when your reserves have been drained, and your fixed expenses put your economy farther and farther into "debt" every second, in a rational world. It defies all common sense.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

The OTA 'tick' system as better in that you didnt have this gradual creep.


And lindir, not all strategy guides for OTA should be taken as gospel, stall is bad, it doesnt matter what game you're playing it is always bad. If you stall its not a good omen that you're spending at the max, it's a bad omen that your economy is weak and isnt producing enough. If yur maxed out its a sign either you need to spend more on military, or you havent been expanding your storage. Storage is there for a reason.

And yes this overdraft could be huge, but it isnt overall, it's per unit, as the overdraft is reset to zero every time it goes over so it could be reset hundreds of times a second with multiple overdrafts.

In OTA your economy stopped and started with spurts every tick. And during each tick you would have your economy run at full blast then drop, then it would start again.

I suggest instead that resource usage stay the same it is but with 2 changes:

- no hard resets to zero.
- Negative values are displayed as zero in the resource bar
- Hard checks are placed in as many places as possible to make sure that you never go overdrawn at all to begin with.

The last one could be done by making the values that store this privte and running everything through get functions, and set functions that return true/false about wether something is affordable.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

But what about things with fixed costs, AF? Not everything can be shut off. Some things cost M/E/sec., but are not called on/off via Activate().

Personally, I think that you should be able to go into the negatives, period. If you cannot afford your fixed expenses... tough. Blow up whatever's spending money you don't have, pay off your debts, and then you're OK again.

The current model basically means that players aren't penalized for living outside their means. It cheats, in short, by erasing any debt incurred on the last SlowUpdate. I think it's lame, now that I understand what it's actually doing :P
User avatar
Snipawolf
Posts: 4357
Joined: 12 Dec 2005, 01:49

Post by Snipawolf »

Perhaps introducing negative values would help... Mod specific of course...

And how far it can go...

I need energy to be able to make things stop, the whole robot race revolves around energy, if they can't make enough, then they should shut down, right?

edit: Argh beat me to the negatives...
Yeha
Posts: 96
Joined: 13 Aug 2004, 19:12

Post by Yeha »

There is no reseting of resources bellow zero, a unit can either pull its requested amount of resources or it won't. If a unit cant pull the requested amount of resources whatever action requested it will fail (unit wont be able to fire, cloak, build, etc)

There is however no priority either, a unit with a fixed energy drain will not use up the energy before anything else can. Having such a system would make a TA style mod a bit anoying, since metalmakers and such would make everything else stall completely.


Get/set MAX_SPEED should (hopefully) be fixed in svn.
User avatar
MadRat
Posts: 532
Joined: 24 Oct 2006, 13:45

Post by MadRat »

When the engine is cycling through units most likely the energy and metal are added as its going through the loop rather than adding it cumulatively at the end of the loop. If you had 96 units in your cycle, with say the 96th making +200 energy, and all units prior to that unit draining every last ounce, the net effect is that you still have +200 energy. If all of the totals were summed before updating a master energy level then you'd see the stall.

Just think how clunky it would be for the units early in the list getting all of the resources from the master energy level before units later in the list. You'd have to sum up the units that needed energy and spread the wealth accordingly to avoid these pitfalls.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

I'll make some screens tonight. Whatever it's doing, it's definately not allowing the economy to go below zero.
User avatar
Fanger
Expand & Exterminate Developer
Posts: 1509
Joined: 22 Nov 2005, 22:58

Post by Fanger »

If they have fixed the hard coded nonsense having to do with needing at least 1 energy/metal to start production, I would really suggest using negative storage to get your complete shutdown. Given that Nano blobs does not neccessarily need 2 resources as income to determine cost, you could use either metal or energy to determine your weapons fire and production and then use negative energy storage to reduce the overall possible energy amount, allowing it to go below zero (zero) and thus cause a shut down.

It seems from what Yeha is saying that this would require a lot of alteration otherwise to get around..
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

If they'd just let the economy go below zero, and make people pay back what they owed, it'd work.

As for proof that things are seriously borked:

Image


In this screenshot, you can clearly see the impossible. I have a negative net income of -24800/sec. I should be so deep in the hole that building anything should be impossible one second after I spawned these Demons and ran out of resources.

This is not what happens. Instead, things continue pretty much as normal- just more slowly, since nanosprays seem to be taking a proportional "bite". Weapons that use Energy don't shut down completely, either- they just have a random chance of being "first in line"- even when there should not be a line because the economy is totally upside down.

As for metal-makers shutting down the economy... that's exactly what they would do in OTA.

GroupAIs can (and should) handle that- or let the Metal Makers handle it themselves, just as they did in OTA, by shutting themselves OFF by setting the ACTIVATION state in their COB to TRUE.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

And the following line in Unit.cpp seems to indicate that I'm not nuts- the cause is correct. Every SlowUpdate, the totals are being set to zero.

Here's the line:

Code: Select all

	metalMakeI=metalUseI=energyMakeI=energyUseI=0;
That's at the start of what looks like the SlowUpdate loop, and explains the bizarre behavior somewhat. However, if you look at my test shot, above, then most SlowUpdates, one of those Demons should be sucking the economy dry before anything else can happen, however this is not what is actually happening. Instead, the Demons' negative costs are being ignored, for all practical purposes. Something else is going here.

And here's yet more hard-coded stuff:

Code: Select all

	if(type==ChangeGiven && unitDef->energyUpkeep>25){//deactivate to prevent the old give metal maker trick
		Command c;
		c.id=CMD_ONOFF;

		c.params.push_back(0);
		commandAI->GiveCommand(c);
Last edited by Argh on 08 Nov 2006, 08:03, edited 1 time in total.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Also, the periodic removal of E/M is not random. Whackily enough, if I read the code right, Cloak gets first priority, then builders.

See the following section:

Code: Select all

	if(wantCloak){
		if(helper->GetClosestEnemyUnitNoLosTest(pos,unitDef->decloakDistance,allyteam)){
			curCloakTimeout=gs->frameNum+cloakTimeout;
			isCloaked=false;
		}
		if(isCloaked || gs->frameNum>=curCloakTimeout){
			float cloakCost=unitDef->cloakCost;
			if(speed.SqLength()>0.2f)
				cloakCost=unitDef->cloakCostMoving;
			if(UseEnergy(cloakCost * 0.5f)){
				isCloaked=true;
			} else {
				isCloaked=false;
			}
		} else {
			isCloaked=false;
		}
	} else {
		isCloaked=false;
	}
Which runs before the next section in the loop, if I'm reading the code right. Interesting.

Code: Select all

bool CUnit::AddBuildPower(float amount,CUnit* builder)
{
	if(amount>0){	//build/repair
		if(!beingBuilt && health>=maxHealth)
			return false;
		
		lastNanoAdd=gs->frameNum;
		float part=amount/buildTime;

		if(beingBuilt){
			float metalUse=metalCost*part;
			float energyUse=energyCost*part;
			if (gs->Team(builder->team)->metal >= metalUse && gs->Team(builder->team)->energy >= energyUse) {
				builder->UseMetal(metalUse);
				builder->UseEnergy(energyUse);
				health+=maxHealth*part;
				buildProgress+=part;
				if(buildProgress>=1){
					if(health>maxHealth)
						health=maxHealth;
					FinishedBuilding();
				}
				return true;
			} else {
				// update the energy and metal required counts
				gs->Team(builder->team)->energyPull += energyUse;
				gs->Team(builder->team)->metalPull += metalUse;
			}
			return false;
		} else {
			if(health<maxHealth){
				health+=maxHealth*part;
				if(health>maxHealth)
					health=maxHealth;
				return true;
			}
			return false;
		} 
Last edited by Argh on 08 Nov 2006, 08:05, edited 1 time in total.
Post Reply

Return to “Engine”