Bug Reports

The problem is canContact is called form the exe, so in my debug stack as soon as it leaves canContact I loose all debug capabilities. I added break points to that function is why I found out it was called. I could just start adding break points all over the place to see what is happening or is there a way to find out what all functions are being called.
 
The problem is canContact is called form the exe, so in my debug stack as soon as it leaves canContact I loose all debug capabilities.
I encountered something like that once and I just kept hitting F11 in the exe code and while the exe itself didn't provide any useful information, it did allow me to step through it. Eventually it ended up in the DLL again and I could see where it entered, which helped quite a lot.
 
I encountered something like that once and I just kept hitting F11 in the exe code and while the exe itself didn't provide any useful information, it did allow me to step through it. Eventually it ended up in the DLL again and I could see where it entered, which helped quite a lot.

Well, it will let me step through the code like that... it goes on and on and on.. how much fn loops does it take to decide if the AI wants to talk?


Anyway, I am out of time so will have to try some more later. Perhaps, I can find where it does this. I am thinking that perhaps there is some kind of fail safe to keep the AI from contacting the player to often... like if the AI_ContactCOunter fails for some reason?? That code is never called. I am suspicious of the setAIContact(true) as it is never used in python or DLL, so I am thinking that perhaps it is used somehow to set up this fail safe. getAIContact is called when beginDiplomacy is called so it must do something. Perhaps, I can set up some scenarios to test this out later.
 
Here is the latest Diplomacy Waiting bug. Remember you can click it, and it does nothing. If you make peace with Rollo, you can then click it and it works :confused:
 

Attachments

  • DiplomacyBUG_with_Rollo_Peace.ColonizationSave
    256.3 KB · Views: 117
  • Debug Diplomacy Peace.ColonizationSave
    252.9 KB · Views: 83
The bug appears to be deep inside the exe and the diplo event is thrown away. Before we had a queue, the AI could make diplo events, which the exe would throw away and we would never notice. Now with the queue, since you never reply, the diplo event is jammed in the queue.

The only thing I can think of is if you click, it starts a counter. This counter is stopped and reset by modifying the queue. If you click for next diplo event from the queue and the counter is higher than a certain number, the front in the queue is kicked out instead of being send to the exe.

We can use CvGame::update() to make the counter go. The exe calls this at fixed intervals, which mean we (sort of) have a real time clock. I'm not sure of the frequency, but a bit of trial and error should make it possible to get a number, which is usable.

I know it's kind of a workaround rather than fixing the problem, but it is the only thing I can think of. I have debugged the savegame and it doesn't matter if the diplo event enters the queue or use vanilla code to enter the exe directly. Either way it dies. I have debugged what the exe calls after getting the diplo event and everything appears to be just fine. It checks for the player having enough gold for his offer, has contact with the player he tries to offer the gold to, is at war with the player he wants to make peace with and stuff like that. All fine, but it just doesn't work.

If nobody has a better idea, I will implement a timer to get rid of broken diplo events and then delete all the debug code. At least that way the game will not stall when this happens. We should make a note of this in the release notes that we are aware of this, but can't do anything about it.

Ok, we can completely avoid using the exe for diplo events, but recoding the entire diplo GUI from scratch is not a trivial task.
 
We may have to use the timer idea. First I want to do some more play testing to see if this is something that happens consistently. If there is certain conditions that happen that sets up this bug then perhaps we can manage to avoid this bug altogether. Like, does the AI offering peace even work normally, maybe its been bugged all along?

Play testing and logging diplomacy calls my reveal a pattern, at least it may tell us which events are bugged.

Each event has a random chance even after all conditions are met. So, for testing this we can removed the random part and then all events will pop when they are able. Perhaps by doing this we can reveal a pattern to this total madness. I call it madness because the DLL does all the necessary checks for diplomacy, but then they redo all the checks in the exe. Perhaps they meant to move most of the code to the dll but never managed it. Like CvDiploParameters is in the DLL but the info written is never used in the DLL.

Here is one thought, you know how with Rollo I could manually ask for peace and then I was able to... I have a thought brb...

Ok, I set it up so that Rollo would ask for peace the next turn, which causes the bug. I then open world builder and force Rollo into Peace, which fixed the Bug:) However, I used world builder again to set us at war and the bug came back. So, it is the condition of War that is causing this apparently. Which makes me think could we trick the exe into thinking we are at peace, to allow the Diplomacy then set us back to war when the screen is popped. Python would know what Diplomacy is called and if the two Players are not at war it could set them to War. Anyway, if being at War causes this bug, then perhaps we can just remove this from delayed responses.

However, this made me realize the system is flawed. As the Player could sue for Peace and then Rollo's request would still be in the que. So, if we left this in Calls for Peace could check the que for the Player and if any requests for present are made we can remove that request. And actually, most of the other requests could be done manually and then they would still be left in the que, so to be realistic most of them would need to check for waiting diplomacy. Or, perhaps better when a Diplomacy is in the que, the owner of it can not be contacted. You get a hover text that says he has diplomats waiting for you already, yeah that would work best.
 
So, it is the condition of War that is causing this apparently. Which makes me think could we trick the exe into thinking we are at peace, to allow the Diplomacy then set us back to war when the screen is popped. Python would know what Diplomacy is called and if the two Players are not at war it could set them to War. Anyway, if being at War causes this bug, then perhaps we can just remove this from delayed responses.
Removing it from delayed response will not fix the issue. I already tried that. However renaming the isAtWar function to isAtWarDLL and then make all DLL functions call the new name. isAtWar() will then only be called by the exe, which mean it shouldn't break anything if it always return false.

However, this made me realize the system is flawed. As the Player could sue for Peace and then Rollo's request would still be in the que. So, if we left this in Calls for Peace could check the que for the Player and if any requests for present are made we can remove that request. And actually, most of the other requests could be done manually and then they would still be left in the que, so to be realistic most of them would need to check for waiting diplomacy. Or, perhaps better when a Diplomacy is in the que, the owner of it can not be contacted. You get a hover text that says he has diplomats waiting for you already, yeah that would work best.
I have been thinking about the same thing. Maybe we need some sort of validator function, which can loop the queue whenever something happens and remove outdated events. Rollo asking for peace after you made peace is a bit silly, but nowhere as critical as a jammed queue.
 
Removing it from delayed response will not fix the issue. I already tried that. However renaming the isAtWar function to isAtWarDLL and then make all DLL functions call the new name. isAtWar() will then only be called by the exe, which mean it shouldn't break anything if it always return false.

Ahh, you are saying the vanilla "issue" of it being rejected by the exe. Well, we don't know for sure it wouldn't break anything, do we? Do we know how often or when the exe calls isAtWar? If it is always false it could send false negatives to the exe which could effect the exe decisions.

I have been thinking about the same thing. Maybe we need some sort of validator function, which can loop the queue whenever something happens and remove outdated events. Rollo asking for peace after you made peace is a bit silly, but nowhere as critical as a jammed queue.

Well, I am thinking it would be easier to code in that if a player attempts to contact an AI Civ, it will cycle through the Responses Waiting to see that player is already waiting, if he/she is it will pop that Diplomacy and prevent the player from normal contacts until that Diplomacy is dealt with. "Hey, contact Rollo for me." "Umm, sir, he already has diplomat's waiting." "Ugh, send them in!"
 
Ok, I just tried my idea... right before the beginDiplomacy is called for the Rollo peace talks I forced them both to Peace with a setAtWar (you have to do this with both teams). This does not display a Message saying so and so declared peace, it just sets the boolean to false. Then I check inside the Python for being at War for the AI_DIPLOCOMMENT_OFFER_PEACE, if they are not, then it sets them to War. This seemingly worked, I clicked the waiting Diplomacy Icon and it went right to Rollo's offer.

If we used this approach we could check the pDiplo->getDiploComment for AI_DIPLOCOMMENT_OFFER_PEACE or for TRADE_PEACE_TREATY in OfferLists. Then we can make them do this work around.

Also, there is a crash bug and it seems also some kind of bug that prevents me from saving the game. The turn that Rollo asks for Peace, if I click the Icon the game crashes, or if I try to save the game it says it can not compress save game file. If I load the Auto Save it all works fine. I think it may have something to do with the setData() in pDiplo. I'll have to check further.
 
Update:

I added this code to the initial cycleDelayedResponses and Rollo appeared the next turn as he should in the cycle. Before he wouldn't appear, you just had the icon appear. I tested letting him wait as well as agreeing to his terms, both worked fine. (forgot to test save game) will do that next.
Code:
int iNum = getNumDelayedResponses();
	if (iNum > 0 && getID() == GC.getGameINLINE().getActivePlayer())
	{
		if (bDisplayAll)
		{
			for (std::list<CvDiploParameters*>::const_iterator ci = m_aDelayedResponses.begin(); ci != m_aDelayedResponses.end(); ++ci)
			{
				CvDiploParameters* pDiplo = new CvDiploParameters(getID());
				*pDiplo = **ci;
				if (pDiplo->getDiploComment() == (DiploCommentTypes)GC.getInfoTypeForString("AI_DIPLOCOMMENT_OFFER_PEACE"))
				{
					PlayerTypes ePlayer = pDiplo->getWhoTalkingTo();
					GET_TEAM(getTeam()).setAtWar(GET_PLAYER(ePlayer).getTeam(), false);
					GET_TEAM(GET_PLAYER(ePlayer).getTeam()).setAtWar(getTeam(), false);
				}
				gDLL->beginDiplomacy(pDiplo, getID());

Edit: saving worked fine

Edit: I'm guessing this works because the Python builds the Diplomacy Comments before it builds the trade table, so the Offer for Peace can be added.
The question is, will this work as a solution?
 
I can see several issues there. Disregarding network sync issues (peace is declared on one computer, but not the other), what if you say no? You already made peace and possibly moved your troops out of his land. They will not move back if you say no.

I think tricking the AI to think you are never at war is the way to go. Presumably it will not have to know about war for anything but this, though we should likely test if it asks for war status for any other diplo event.
 
I can see several issues there. Disregarding network sync issues (peace is declared on one computer, but not the other), what if you say no? You already made peace and possibly moved your troops out of his land. They will not move back if you say no.

I think tricking the AI to think you are never at war is the way to go. Presumably it will not have to know about war for anything but this, though we should likely test if it asks for war status for any other diplo event.

There should be no sync issues and you have no time to move troops or change your mind. You must not have understood what I did. The dll sets the players to peace, beginDiplomacy is immediately sent to exe, exe sees they are at peace and sends it on to Python, Python then sets them back to war, no network out of sync or other exploits. The Player gets a Diplomacy screen with him being at War and must decide if he wants Peace or War, life continues as usual.

I'm not convected that having a constant atWar set to false will not lead to issues. Obviously atWar is called many times by the Exe for diplomacy issues and it would seem that it would need this to be correct. There is only about 60 times it appears in the DLL and python so it wouldn't be that huge of a deal to change it however, but you would have to do the work for a atWarDLL before you could really test it out.

I remember that the Animal mod set the Barbarian player to atWar with everyone. This caused lots of diplomacy issues because the AI would not do certain Diplomacy with you because you where at War, like it wouldn't do a defensive pact anymore. So, I fixed this issue with the Barbarian units being all Hostile instead. So, I am suspicious that the exe never knowing if Players are at war could cause issues, but maybe not.

Edit: We don't even know yet if this is a constant bug. What if sometimes it works correctly, then offers of Peace would be killed off in the Exe if atWar is always true. So, first we need to test more.
 
Something strange went on, one of the Civs appeared and asked for a Defense Pact, but I was at War with him so this should never have happened. The Deal wasn't visible on the trade menu anyway. I investigated a bit, but didn't make sense of it so just declined and moved one. Will have to check into this later if it ever happens again.

Ok, I discovered one reason why it was so hard to gain Fealty. Fealty is calculated on a Team basis. Your whole team counts together, so if you have Vassals you are counting his cities as well, which gain no Fealty, so you have to cover all his cities with only the Fealty in your cities. Anyway, until Vassals can generate Fealty I have removed none Humans for the Fealty count if there is a Human on the team.
 
Vassals!!!! [pissed]

that could be another good use of a diplomat style unit in the future, to 'pump' fealty into your vassal courts, working a bit like the tax collector.

Yeah, that is a good Idea. Before I made the change I was at 45% struggling to get up to 50%, maybe a point every other turn or so. Then after the change I was at 57% with 25 turns left to go:)
 
We could move Fealty to count for each player rather than teams. Vanilla teams seems to be good for just one thing, which is to make two human players play together as one country where they share founding fathers and stuff like that. We have moved more towards a player orientated setup where all team members aren't equal. They (unlike vanilla BTS) don't have to have the same inventions and stuff like that.

I view vassals of kind of like conquered land, well they kind of surrendered. I view Fealty as some kind of nationalism, as in how much the people like their leader. Kind of like the Roman empire. They conquered land, but they didn't really care how much the people loved Caesar as long as they honoured requests and paid taxes. The only place where the will of the people were really important was in Rome itself. Everybody else were just barbarians or other kinds of lower rating people. Romans considered Rome to be perfect and their view on other countries dropped for each thing, which weren't identical to Rome. So what if the Britons made better armour because their blacksmiths had mastered making chainmails? Rome didn't use chainmails, meaning it would be wrong to use them, regardless of how well they worked. After all Rome was perfection.
 
But this is really a different system to rome, as this is feudal, with kings and vassals, these conquered lands may be given to one of your noble lords, but their fealty was still important, and intrigue amongst disgruntled lords was rife.

So eventually having to manage the 'support' of your vassal lords would be important, especially once we get to the stage of being able to empower and increase the strength of vassals. As a collective of disgruntled but incresingly powerful lords could become a real threat.
 
Therefore, as fealty shouldn’t be produced, but fealty should be a result instead, that moves to the proposed system of “people’s necessities being covered” that will turn into increased fealty. Greedy lords who want all goods being traded away may leave their people poorly dressed and fed, these people wouldn’t love their lord; and well fed people are more unlikely to revolt. I love this system, but how can the AI know that a constant supply of coats must arrive and being distributed among the citizens to have them well dressed and happy?

To me, an easier way to tackle with that is through diplomacy. You give your vassal loads of wine and money and his fealty would increase (again it is not produced but it is a result). That’s ok with your vassal civs, but how to deal this way with your own people? You couldn’t start diplomatic relations with yourself and trade loads of wine to have your own fealty increased.

Besides, I also find more strategically enjoyable the “people’s necessities being covered” system to produce fealty, but that may be a big change.
 
Top Bottom