Single Player bugs and crashes - After the 24th of February 2014

I tested a bit more and came to the following conclusion: The popup occurs with Guard, Settler, Monk, Apothecary, Missionaries but not with Longbowman, Flailman. Usually 2 popups for every unit produced. Looks like producing non-combat units and units which can only defend are the cause for popups in my game.

Would disabling advisor popups get rid of them?
If disabling the advisers does ge rid of them then it is that that is causing the problems. I am not getting the pop up when I build those units. let me just check that I have updated with the latest of that file and that I am using the latest of the rest.

If y'all would ever read what I post from my diagnostic reports in this thread you'd know that I had to hedge the code against a crash that was taking place against python calling for a NULL Feat definition somewhere. This must certainly be the problem as I only added a workaround that keeps it from crashing. I hadn't seen this problem until I had to find and resolve it and in the wake of resolving it on the dll side I began seeing the reported empty event popup. The python end of it still needs fixing and I had no idea where it suddenly started coming from since I'd not seen anything discussed about Feats being worked with.

Platyping put out a new version of the python that significantly reduces game turn time later in the game. The later in the game it is the more time is saved.
 
Platyping put out a new version of the python that significantly reduces game turn time later in the game. The later in the game it is the more time is saved.
Ok but it needs to stop trying to call for a null feat definition into the code. It wouldn't be able to get away with that in any mod - I've at least made it possible for us to get through it without crashing but it will cause delay until resolved.
 
1) 99% it is due to Combat Feats to get an Empty "" as Text.

Change line 137
Code:
popupInfo.setText(CyTranslator().getText(lUnitCombat[iCombat][1], (pUnit.getNameKey(), pCity.getNameKey(),)))

to
Code:
popupInfo.setText(pUnit.getName() + " " + pCity.getName())

to identify the culprit.

I am pretty sure you cannot replicate the same problem in BTS, so it may be because of units with multiple combat class in your mod.

2) Never ever play with advisors activated in a big mod... if you ever read the codes.
 
One question, does platypings or the vanilla code cover all unitcombat_types for unit building feats and if so would including all of C2Cs unitcombat_types in the building_units part fix this?

Edit: eh well, apparently too late :)
 
That's probably it but those were removed from that python due to a huge slowdown in the bug options page they were causing.

There SHOULD be a way of keeping the final python call from taking place if it's about to call with a null reference. The null reference is fine in the python but it causes trouble in the dll. If it can be stopped from calling to the dll with the null ref if there's a null ref it wants to call it'd be the easiest fix.
 
Takes less than 10 sec to add in such a code, just that it wasn't crashing anything in BTS :)
 
It depends on what getUnitCombatType() on the unit is returning. If it is a list of unit types then there will be a problem but if it is just a single number then there is no problem.

In the latter case we can probably generate the feat text in some way that is compatible across languages or we can just report those that have a feat already defined. depends on where we want to go with this. After all these are the things that triggered the building of your Throne Room in Civ III and your Palace in earlier versions.
 
Takes less than 10 sec to add in such a code, just that it wasn't crashing anything in BTS :)

Which suggests that tis is not the place where the crash is occurring because not all combat classes lead to a feat in BTS either so it would be handling the empty string. Which is not the same thing as NULL anyway.
 
Well... exactly. Since the class tag is loaded after the AndDependencyTypes and the UnitClassInfos are loaded before the UnitInfos how on earth are we having this:

That sounds like whatever 'error' DH is having with this is perhaps not to be construed in the manner in which he expressed here. Given what you just said (and I would concur with my limited knowledge here) what he said in the quoted portion there should NOT be taking place at all! He shouldn't have any trouble putting an AndDependency on the infos object itself!

@DH: This certainly warrants more investigation and discussion. That comment should not be correct. So I'm wondering what's 'really' taking place there.


If a UnitClass has a AndDependency to the unit itself it fails because the unit has not been loaded at that time. The same goes for a BuldingClasses with Buildings as AndDependency.......
This suggests the unit is missing a AndDependency to the UnitClass and shows that the AndDependencyTypes tag has some limits.


Examples could help here.
 
Again, the python is an odd problem where it's checking for an event that is somehow getting an index value but that value is out of range so perhaps its a loop that isn't limited to the number of event trigger indexes?

There might be a problem in the game save and load mechanism.

Code:
void EventTriggeredData::read(FDataStreamBase* pStream)
{
	CvTaggedSaveFormatWrapper&	wrapper = CvTaggedSaveFormatWrapper::getSaveFormatWrapper();

	wrapper.AttachToStream(pStream);

	WRAPPER_READ_OBJECT_START(wrapper);

	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iId);
	[COLOR="Red"][B]WRAPPER_READ(wrapper, "EventTriggeredData",(int*)&m_eTrigger);[/B][/COLOR]
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iTurn);
	WRAPPER_READ(wrapper, "EventTriggeredData",(int*)&m_ePlayer);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iCityId);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iPlotX);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iPlotY);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iUnitId);
	WRAPPER_READ(wrapper, "EventTriggeredData",(int*)&m_eOtherPlayer);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iOtherPlayerCityId);
	
	//	Expiration was not stored in older saves (which didn;t store expired events for replay)
	//	so default to false if absent
	m_bExpired = false;
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_bExpired);

	WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData",REMAPPED_CLASS_TYPE_RELIGIONS,(int*)&m_eReligion);
	WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData",REMAPPED_CLASS_TYPE_CORPORATIONS,(int*)&m_eCorporation);
	WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData",REMAPPED_CLASS_TYPE_BUILDINGS,(int*)&m_eBuilding);
	WRAPPER_READ_STRING(wrapper, "EventTriggeredData",m_szText);
	WRAPPER_READ_STRING(wrapper, "EventTriggeredData",m_szGlobalText);

	WRAPPER_READ_OBJECT_END(wrapper);
}

void EventTriggeredData::write(FDataStreamBase* pStream)
{
	CvTaggedSaveFormatWrapper&	wrapper = CvTaggedSaveFormatWrapper::getSaveFormatWrapper();

	wrapper.AttachToStream(pStream);

	WRAPPER_WRITE_OBJECT_START(wrapper);

	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iId);
	[COLOR="Red"][B]WRAPPER_WRITE(wrapper, "EventTriggeredData", m_eTrigger);[/B][/COLOR]
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iTurn);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_ePlayer);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iCityId);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iPlotX);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iPlotY);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iUnitId);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_eOtherPlayer);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iOtherPlayerCityId);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_bExpired);
	WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_RELIGIONS, m_eReligion);
	WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_CORPORATIONS, m_eCorporation);
	WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_BUILDINGS, m_eBuilding);
	WRAPPER_WRITE_STRING(wrapper, "EventTriggeredData", m_szText);
	WRAPPER_WRITE_STRING(wrapper, "EventTriggeredData", m_szGlobalText);

	WRAPPER_WRITE_OBJECT_END(wrapper);
}

This completely ignores the fact that EventTriggers could be added, reordered or removed.
It should be something like this
Code:
WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_EVENT_TRIGGERS,(int*)&m_eTrigger);
and
Code:
WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_EVENT_TRIGGERS, m_eTrigger);

And all the usages of m_eTrigger must also check for a -1(NO_EVENTTRIGGER) in there.
 
In CIV4BuildInfos.xml (/XML/Units), the Moai improvement build has a <Description> of TXT_KEY_BUILD_MOAI_STATUES. It should be TXT_KEY_BUILD_MOAI.
 
Which suggests that tis is not the place where the crash is occurring because not all combat classes lead to a feat in BTS either so it would be handling the empty string. Which is not the same thing as NULL anyway.
Ah but it is the same - any unrecognized value will register as -1 in the dll and in this case that's what's being called by the python so it very likely IS the problem and all we need to do is keep the python from calling any value of -1 (the indexed value of -1 anyhow.)

It depends on what getUnitCombatType() on the unit is returning. If it is a list of unit types then there will be a problem but if it is just a single number then there is no problem.

In the latter case we can probably generate the feat text in some way that is compatible across languages or we can just report those that have a feat already defined. depends on where we want to go with this. After all these are the things that triggered the building of your Throne Room in Civ III and your Palace in earlier versions.
getUnitCombatType() would return the single value of the unit's primary combat class. If it returns one unrecognized by the python it may well return a -1. Anyhow, none of this should be an issue... Just keeping the call from being able to send a -1 should be enough to fix the whole concern.
If a UnitClass has a AndDependency to the unit itself it fails because the unit has not been loaded at that time. The same goes for a BuldingClasses with Buildings as AndDependency.......
This suggests the unit is missing a AndDependency to the UnitClass and shows that the AndDependencyTypes tag has some limits.


Examples could help here.
My understanding is that what DH is saying went beyond this. That, of course, makes sense what you just said. But I believe he's trying to say that he can't set any AndDependency for the unit CLASS object without it causing a problem. This would mean that if he tried to put a Dependency on both the class and the info objects that was the same and based on a common element (which is the way this really SHOULD be established to do this in the safest manner) that no matter what the load process order, he's going to have a problem. So the REAL issue is, what's making it problematic for him to define an And Dependency for the unit Class at all?


@DH: There's no way it really ever could've been fine to define a Class Object's AndDependency on the unit or building AND vice versa - that would be completely impossible to code as it is a paradox in itself. But if I'm beginning to understand you right, NO dependency is working for the class object right?

There might be a problem in the game save and load mechanism.

Code:
void EventTriggeredData::read(FDataStreamBase* pStream)
{
	CvTaggedSaveFormatWrapper&	wrapper = CvTaggedSaveFormatWrapper::getSaveFormatWrapper();

	wrapper.AttachToStream(pStream);

	WRAPPER_READ_OBJECT_START(wrapper);

	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iId);
	[COLOR="Red"][B]WRAPPER_READ(wrapper, "EventTriggeredData",(int*)&m_eTrigger);[/B][/COLOR]
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iTurn);
	WRAPPER_READ(wrapper, "EventTriggeredData",(int*)&m_ePlayer);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iCityId);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iPlotX);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iPlotY);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iUnitId);
	WRAPPER_READ(wrapper, "EventTriggeredData",(int*)&m_eOtherPlayer);
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_iOtherPlayerCityId);
	
	//	Expiration was not stored in older saves (which didn;t store expired events for replay)
	//	so default to false if absent
	m_bExpired = false;
	WRAPPER_READ(wrapper, "EventTriggeredData",&m_bExpired);

	WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData",REMAPPED_CLASS_TYPE_RELIGIONS,(int*)&m_eReligion);
	WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData",REMAPPED_CLASS_TYPE_CORPORATIONS,(int*)&m_eCorporation);
	WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData",REMAPPED_CLASS_TYPE_BUILDINGS,(int*)&m_eBuilding);
	WRAPPER_READ_STRING(wrapper, "EventTriggeredData",m_szText);
	WRAPPER_READ_STRING(wrapper, "EventTriggeredData",m_szGlobalText);

	WRAPPER_READ_OBJECT_END(wrapper);
}

void EventTriggeredData::write(FDataStreamBase* pStream)
{
	CvTaggedSaveFormatWrapper&	wrapper = CvTaggedSaveFormatWrapper::getSaveFormatWrapper();

	wrapper.AttachToStream(pStream);

	WRAPPER_WRITE_OBJECT_START(wrapper);

	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iId);
	[COLOR="Red"][B]WRAPPER_WRITE(wrapper, "EventTriggeredData", m_eTrigger);[/B][/COLOR]
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iTurn);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_ePlayer);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iCityId);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iPlotX);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iPlotY);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iUnitId);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_eOtherPlayer);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_iOtherPlayerCityId);
	WRAPPER_WRITE(wrapper, "EventTriggeredData", m_bExpired);
	WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_RELIGIONS, m_eReligion);
	WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_CORPORATIONS, m_eCorporation);
	WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_BUILDINGS, m_eBuilding);
	WRAPPER_WRITE_STRING(wrapper, "EventTriggeredData", m_szText);
	WRAPPER_WRITE_STRING(wrapper, "EventTriggeredData", m_szGlobalText);

	WRAPPER_WRITE_OBJECT_END(wrapper);
}

This completely ignores the fact that EventTriggers could be added, reordered or removed.
It should be something like this
Code:
WRAPPER_READ_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_EVENT_TRIGGERS,(int*)&m_eTrigger);
and
Code:
WRAPPER_WRITE_CLASS_ENUM(wrapper, "EventTriggeredData", REMAPPED_CLASS_TYPE_EVENT_TRIGGERS, m_eTrigger);

And all the usages of m_eTrigger must also check for a -1(NO_EVENTTRIGGER) in there.

Awesome! Thanks! That may well help - I'll be happy to test that as soon as I CAN which may not be too soon yet.
 
SVN 7707.

An Entertainer can build "Stories about Bears" when it has already been built in another city. It grants "Story about bears" in every city, but they already have it.
 
OK, updating to the latest version of things in the SVN means that I am getting the problem with the popup with the two buttons that Stormwind has. So I have replicated the problem.

As expected updating with the very latest by Platyping fixes the problem. I'll update the SVN soon.

(I am a bit distracted at the moment - Mum went into hospital for a hip replacement very suddenly. Everything is OK and she is up and walking.)
 
OK, updating to the latest version of things in the SVN means that I am getting the problem with the popup with the two buttons that Stormwind has. So I have replicated the problem.

As expected updating with the very latest by Platyping fixes the problem. I'll update the SVN soon.
)

So it was the changes then YOU made that caused this?? In what revision was it?
 
@DH: There's no way it really ever could've been fine to define a Class Object's AndDependency on the unit or building AND vice versa - that would be completely impossible to code as it is a paradox in itself. But if I'm beginning to understand you right, NO dependency is working for the class object right?

1) Putting an And dependency on the building infos causes an error on the class because it can't find the default building.

2) Putting an And Dependency on the class causes an error on the infos because the class does not exist.

3) Putting an And Dependency on both causes the same error as 2)

I have not tested the case where there are multiple building infos for a single class.
 
So it was the changes then YOU made that caused this?? In what revision was it?

No. TB was getting errors in the dll. His fix caused that pop-up to happen. At the same time Platyping came up with a way of improving the game turns especially in the late game where it is needed. These changes had no impact on the error. This can be seen since it is only C2C that gets the problem.

The code in BTS is perhaps not the best and does not do all the error checking it should. As the dll programmers improve the code it becomes more important to catch the "small" errors so that they don't grow into CtD's.

I would have done Platyping's change slightly differently so as to use less memory. Instead of making an array with all the unit combat classes in I would have only put in those that we want feats on... this difference would be negligible in most mods but not in C2C;)
 
1) Putting an And dependency on the building infos causes an error on the class because it can't find the default building.
If you're designating the class object as that which the infos object is dependent on, yes, that will quite naturally happen for that reason.

2) Putting an And Dependency on the class causes an error on the infos because the class does not exist.
If the info isn't also being dependent on the same object, yes, if the class dissapears out from under the info object it'll cause problems for the info object. That makes sense.

3) Putting an And Dependency on both causes the same error as 2)
You mean making the AndDependency defined as the class object for the info object and the info object for the class object? Of course that would be a problem!

The solution is, and I suspect would always have had to have been: Make them both dependent on the SAME object AND make it neither of them! You'd NEED a third party object to designate as that which the objects are dependent on, even if it's something like a dummy tech or something that WILL load before building classes and unit classes! Something that will only exist if the module you want them dependent on is active.

If you want one unit dependent on another unit that's modularized that's easy... make the class dependent on the corresponding unit CLASS object and the unit dependent on the corresponding UNIT object.

Doesn't THIS work?

No. TB was getting errors in the dll. His fix caused that pop-up to happen.
Might just be a matter of the terminology but I feel it's important to clarify: NO, my fix did NOT CAUSE the popup to happen, it ALLOWED the null reference to pass and thus allowed the popup to take place despite the call returning a false result back to python. I presume that the popup was blank because the return was false and the python had never been prepped for that possibility (aka the popup was already called and the list was being generated for the options the popup would give and one or all of the items on that list included that NO_FEAT call itself so when it returns false, the pop's already manifesting but there's no list to accompany it so it ends up blank.)

As the dll programmers improve the code it becomes more important to catch the "small" errors so that they don't grow into CtD's.
We can't hedge against all presumptions firaxis made when developing the code. They appear to have been very clear within their team communications what would be necessary to prepare for (as in what COULD be negative and what could NOT - we've violated many of those presumptions they originally made for example) and coded according to those gamerule assumptions. Those lurk all over the place and in most cases they actually do have a little efficiency factor and built-in error checking factors that we wouldn't want to disable unless it proves that we need to - usually found by a mod doing something that was not planned for like this.

aka... it's not an error or 'bad design' so much as a programming presumption that only becomes an error when someone violates that presumption without realizing the presumption had been made. Civ's got all sorts of those pit traps all over the code. I've run afoul of and had to tweak the code with these on numerous occasions!

I would have done Platyping's change slightly differently so as to use less memory. Instead of making an array with all the unit combat classes in I would have only put in those that we want feats on... this difference would be negligible in most mods but not in C2C;)
You seem to have discovered what was at the heart of the problem there so good job with that (to both you and platy!) Thanks!
 
I've got villages saying "improvement denied upgrade" but I've never been given the option. I set them unworked and then worked again, and the status changes to "1 turn to Town...or...". But then next turn they are back to "denied upgrade".

Save available...
 
I've got villages saying "improvement denied upgrade" but I've never been given the option. I set them unworked and then worked again, and the status changes to "1 turn to Town...or...". But then next turn they are back to "denied upgrade".

Save available...

This is by design but it could help to explain why it's happening:

There's a primary upgrade defined. When that primary upgrade is tech accessed the countdown begins to upgrade. When the countdown ends, there are some times and positions where the primary upgrade is not valid. If it is not AND there are no other alternative upgrades defined that ARE valid in that position then it will immediately freeze the upgrade (this is so it doesn't destroy processing times by checking every pending upgrade plot every round.) You can and should unlock it, just as you've determined you can do, every so often to see if other options may have opened up.

At some point it needs to be fully explained in the pedia I know but that effort is just too great at the moment.

This display of the upgrade chains and their alternatives at each juncture where alternatives are defined may be rather illuminating.

So an example:

A seed camp is built inland and away from a river. The Farm is its primary upgrade. But the Farm cannot be upgraded into unless the plot is irrigated (which for a while will mean that the plot must be adjacent to a source of freshwater like a river, a freshwater lake or a city that produces freshwater from a building) so for this seedcamp, unless it can upgrade into an alternative it will freeze. You won't get an option when it finds an alternative, it'll just do it if its possible to do, so, say you have cottages accessed, it'll just pop into a cottage instead unless there's a good reason it can't according to the cottage.

So in this example, the player who's sorted it all out will want to unlock the seedcamp's freeze once the cottage is available by tech or the plot has become irrigated and is thus capable to become a farm.


The trigger for the option list to come up for you to select the upgrade is ONLY when the default or next possible upgrade will naturally destroy the FEATURE that exists on the plot. At that point you have options - including voluntarily freezing the upgrade if you don't want to allow the upgrade (if you have no non-destructive options) to destroy the feature.


Complicated I know but designed in mind for all possible complaints. Including streamlining to keep it from causing turn time problems. (With the one complaint I couldn't solve for being the complaint that it was too complex to easily figure out what was really taking place, what is and what is NOT a bug.)
 
Back
Top Bottom