Variable increment issue

Ok, weird issue here. I have the following variables set in this exact order:

1
2
3
4
5
b8 cnrIsModeGood = false;
u32 cnrGoodModel = 0;
u32 cnrBadModel = 0;
u32 cnrMaxBad = 30; //SET THIS APPROPRIATELY
u32 cnrMaxGood = 7; // SET APPROPRIATELY 


I can change the cnrIsModeGood to true and false, and I can increment the cnrBadModel. I, however, cannot increment cnrGoodModel no matter what I do. So I moved the boolean to the bottom like this:

1
2
3
4
5
u32 cnrGoodModel = 0;
u32 cnrBadModel = 0;
u32 cnrMaxBad = 30; //SET THIS APPROPRIATELY
u32 cnrMaxGood = 7; // SET APPROPRIATELY
b8 cnrIsModeGood = false;


I can now INCREMENT the cnrGoodModel but not the cnrBadModel now.. WTF? I have hours trying to figure this out.

This shouldn't matter but my PC specs:
MS VC++ 2010
Windows 7 x64 Ultimate

NOTE:
It doesn't matter how I try to increment: cnrGoodModel++, cnrGoodModel += 1, cnrGoodModel = cnrGoodModel + 1 it WONT WORK. These variables are in the global scope which is where they need to be.

Edit: u32 is just a typedef for unsigned int, and b8 is a typedef for boolean

EDIT2: WTF. Ok, I just added two bogus (meaning I will never use) variables on the very top... now everything is incrementing fine. I really wish someone could tell me wtf is going on here.
Last edited on
Edit: u32 is just a typedef for unsigned int, and b8 is a typedef for boolean

And boolean is a typedef for bool? ;)

This is strange. Could you post the full code?
1
2
typedef unsigned int u32;
typedef bool b8;


With the above code, I can declare booleans and unsigned integers like the code above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#include "CustomFiberThread.h"
#include "Scripting.h"
#include "../ScriptHook/Log.h"

#include <windows.h>
#include "KeyboardManager.h"
//#include "Variables.h"
#include <cstdio>

// Pull in all our scripting functions/types
using namespace Scripting;

i32 crap01 = 0; // Added crap01=0 and crap02=0 now cnrGoodModel and
i32 crap02 = 0; // cnrBadModel increment fine. Remove them and only one increments
i32 cnrGoodModel = 0;
i32 cnrBadModel = 0;
i32 cnrMaxBad = 29; //SET THIS APPROPRIATELY
i32 cnrMaxGood = 7; // SET APPROPRIATELY
b8 cnrIsModeGood = false;

Scripting::eModel cnrCopModels[8] = {MODEL_M_M_FATCOP_01,MODEL_M_M_FBI,MODEL_M_M_SECURITYMAN,MODEL_M_Y_COP,MODEL_M_Y_COP_TRAFFIC,MODEL_M_Y_STROOPER,MODEL_M_Y_SWAT,MODEL_IG_FRANCIS_MC};
Scripting::eModel cnrBadModels[30] = {MODEL_M_M_GBIK_LO_03,MODEL_M_Y_GBIK_HI_01,MODEL_M_Y_GBIK_HI_02,MODEL_M_Y_GBIK02_LO_02,MODEL_M_Y_GBIK_LO_01,MODEL_M_Y_GBIK_LO_02,MODEL_M_Y_GMAF_HI_01,MODEL_M_Y_GMAF_HI_02,MODEL_M_Y_GMAF_LO_01,MODEL_M_Y_GMAF_LO_02,MODEL_M_M_ALCOHOLIC,MODEL_M_M_CRACKHEAD,MODEL_M_M_ENFORCER,MODEL_M_M_GUNNUT_01,MODEL_M_O_MPMOBBOSS,MODEL_M_Y_DEALER,MODEL_M_Y_DRUG_01,MODEL_M_Y_GOON_01,MODEL_M_Y_PRISON,MODEL_M_Y_THIEF,MODEL_M_Y_JIM_FITZ,MODEL_M_Y_DODGY_01,MODEL_M_Y_STREET_01,MODEL_M_Y_STREET_03,MODEL_M_Y_STREET_04,MODEL_M_Y_STREETBLK_02,MODEL_M_Y_STREETBLK_03,MODEL_M_Y_STREETPUNK_02,MODEL_M_Y_STREETPUNK_04,MODEL_M_Y_STREETPUNK_05};

CustomFiberThread::CustomFiberThread()
{
    // Give your own name here!
	SetName("CnrAssistant");
}

// Some helper functions

Player CustomFiberThread::GetPlayer()
{
	Player playerIndex = ConvertIntToPlayerIndex(GetPlayerId());
	return playerIndex;
}

Scripting::Ped CustomFiberThread::GetPlayerPed()
{
	Ped ped;
	GetPlayerChar(GetPlayer(), &ped);
	return ped;
}


void CustomFiberThread::SpawnCar(eModel model)
{
	RequestModel(model);

	while(!HasModelLoaded(model))
	{
		Wait(0);
	}

	LogInfo("Car model available... spawning it!");

	Ped ped = GetPlayerPed();

	Vehicle vehicle;
	f32 x,y,z;

	GetCharCoordinates(ped, &x, &y, &z);

	CreateCar(model, x, y, z, &vehicle, true);

	MarkModelAsNoLongerNeeded(model);

}

void CustomFiberThread::ChangePlayerSkin(eModel model)
{
	RequestModel(model);

	while(!HasModelLoaded(model))
	{
		Wait(0);
	}

	LogInfo("Skin model available... spawning it!");

	eInteriorRoomKey roomKey;
	
	GetKeyForCharInRoom(GetPlayerPed(), &roomKey);

	ChangePlayerModel(GetPlayer(), model);

	SetRoomForCharByKey(GetPlayerPed(), roomKey);

	MarkModelAsNoLongerNeeded(model);

}

void CustomFiberThread::TeleportToWaypoint(Scripting::Ped &ped)
{
    Blip b = GetFirstBlipInfoId(BLIP_WAYPOINT);
    if(b.IsValid())
    {
        Vector3 v;
        GetBlipCoords(b, &v);

        LogInfo("Teleporting to %f, %f", v.X, v.Y);

        // Thanks to Prince-Link for this magical Z coord detection code...
        SetCharCoordinates(ped, v.X, v.Y, v.Z);
        while(v.Z == 0.0f) // The chance that ground Z is 0.0 _exactly_ is really small
        {
            GetGroundZFor3DCoord(v.X, v.Y, 1000, &v.Z);
            Wait(0);
        }

        SetCharCoordinates(ped, v.X, v.Y, v.Z);
    }
    else
    {
        LogError("No way point found to teleport to.");
    }

}

void CustomFiberThread::OutputEx(char *displayString)
{
	PrintStringWithLiteralStringNow("STRING", displayString, 2000, 1);
	LogInfo("OUTPUT EX USED");
}

void CustomFiberThread::CycleModels()
{
	if ( cnrIsModeGood )
	{
		if (Hotkey[RIGHT].pressed) {
			if(++cnrGoodModel > cnrMaxGood) {
				cnrGoodModel = 0;
			}
			ChangePlayerSkin(cnrCopModels[cnrGoodModel]);


		}else if (Hotkey[LEFT].pressed) {
			if(--cnrGoodModel < 0) {
				cnrGoodModel = cnrMaxGood;
			}
			ChangePlayerSkin(cnrCopModels[cnrGoodModel]);
		}
	}
	else
	{
		if (Hotkey[RIGHT].pressed) {

			if(++cnrBadModel > cnrMaxBad) {
				cnrBadModel = 0;
			}

			ChangePlayerSkin(cnrBadModels[cnrBadModel]);

		}else if (Hotkey[LEFT].pressed) {

			if(--cnrBadModel < 0) {
				cnrBadModel = cnrMaxBad;
			}

			ChangePlayerSkin(cnrBadModels[cnrBadModel]);
		}
	}
	
	SetAnimGroupForChar(GetPlayerPed(), "move_player");
}

void CustomFiberThread::CycleCurrentModel()
{
	eModel GetCurMod;
	if (cnrIsModeGood) {
		GetCurMod = cnrCopModels[cnrGoodModel];
	}else{
		GetCurMod = cnrBadModels[cnrBadModel];
	}

	ChangePlayerSkin(GetCurMod);
	SetAnimGroupForChar(GetPlayerPed(), "move_player");
}

void CustomFiberThread::IncrementTest() {
	// USE AS TESTER FUNCTION
}


// The real script

void CustomFiberThread::RunScript()
{
	// This is a fiber thread, so we use an loop to run the contents of this script.
	// The thread will terminate when we return from this function.
	keyboard_init();
	while(IsThreadAlive())
	{
		keyboard_watch();
		
		if ( Hotkey[CONTROL].pressed && Hotkey[DOWN].pressed ) 
		{
			cnrIsModeGood = !cnrIsModeGood;
			OutputEx((cnrIsModeGood ? "Mode Set To: Good" : "Mode Set To: Bad"));
		}
		else if ( Hotkey[CONTROL].pressed && ( Hotkey[RIGHT].pressed || Hotkey[LEFT].pressed ) )
		{
			CycleModels();
		}
		else if ( Hotkey[CONTROL].pressed && Hotkey[ENTER].pressed )
		{
			CycleCurrentModel();
		}
		Wait(100);

	}


}
Are you able to debug and step into CycleModels? Are there multiple threads running (i.e. is the increment failure due to a race condition)?
I am not sure if I can debug it or not. This project is a DLL addon to a full screen directx game. In order for me to test it I have to compile, rename, and drop the renamed dll in to a certain folder then load the full screen game. Most games you can ALT-TAB out of but this one wont come back up once you have done so. Before I put the two bogus variables at the top, I tried manually increasing the variable through a hotkey function.. matter-of-fact, I tried increasing/decreasing 4+ variables by one at one key press.. all but one would increase. Then of course in my original top post where I said I moved a boolean variable below the rest, I could then increment the one variable that wouldn't increment, but then another variable wouldn't increment at all. Of course, just out of curiousity, I put those two bogus variables at the top and now all the variables increment fine. I have not however tried incrementing the bogus variables because I havent the need to do so, as they are bogus. Still, this doesn't sound right and I don't want this to come back and bite me near project completion. As for race conditions, im still a noob to C++ and am unfamiliar with this term. If it helps, the DLL project is based on Fiber threading.
As for race conditions, im still a noob to C++ and am unfamiliar with this term.

Essentially, a race condition can occur if multiple threads access the same resource (i.e. a variable) at the same time. For instance, let's say that two threads are executing the method CycleModels simultaneously. One thread executes the line if(++cnrBadModel > cnrMaxBad) then goes to a sleep state. Then, the other thread executes the line if(--cnrGoodModel < 0), the variable cnrGoodModel would have incremented and then decremented right after, giving the impression that the variable had not changed. Is it possible for multiple fibers/threads to be running methods in your given code at the same time? If so, a race condition can occur with the global variables. One way of fixing this would be to make the global variables as member variables of CustomFiberThread.

I am not sure if I can debug it or not.

If proper debugging is impossible and/or cumbersome then I would suggest "printf" debugging, or in this case, "MessageBox" debugging.

For instance, I would place calls to MessageBox at strategic locations in your code. You said that the incrementing of those variables appears to not happen. It looks like the method CycleModels is in charge of that. I would start by placing calls to MessageBox in it like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void CustomFiberThread::CycleModels()
{
	if ( cnrIsModeGood )
	{
		if (Hotkey[RIGHT].pressed) {
                        MessageBoxA(GetActiveWindow(), "cnrIsModeGood  Hotkey[RIGHT].pressed", "", 0);
			if(++cnrGoodModel > cnrMaxGood) {
                                MessageBoxA(GetActiveWindow(), "if(++cnrGoodModel > cnrMaxGood) passed", "", 0);
				cnrGoodModel = 0;
			}
                        char buffer[100];
                        itoa(cnrGoodModel, buffer, 10);
                        MessageBoxA(GetActiveWindow(), buffer, "", 0);

			ChangePlayerSkin(cnrCopModels[cnrGoodModel]);

		}...


and so on. If message boxes interfere with the program flow too much, then you can write the messages to a file instead. You can then examine the file after exiting the program. Hopefully this can help you narrow down the source of this bug.
I have done something of that sorts by doing this:

1
2
3
char displayString[300];
sprintf_s(displayString, 300, "cnrGoodModel: %d  cnrBadModel: %d", cnrGoodModel++, cnrBadModel++); //Copy over variable value, then increment for next round
OutputEx(displayString); //Output to game screen 


This would output the following in-game, one line at time per pressing of "SHIFT"

1
2
3
4
cnrGoodModel: 0  cnrBadModel: 0
cnrGoodModel: 1  cnrBadModel: 0
cnrGoodModel: 2  cnrBadModel: 0
cnrGoodModel: 3  cnrBadModel: 0


Notice cnrBadModel wasn't incrementing, yet they are both declared and initialize in the same scope.

Also, the project is single thread.
Last edited on
The code you posted looks OK. The problem is probably due to some undefined behaviour happening in some other code. What about the bogus variables? Have you tried incrementing them? If you initialize them to 1 to they get set back to zero?
If I increment "int crap01", I cannot increment "int crap02" and vice versa. Since I put those two at the top, everything else is working fine.

Im using C++ 2010 SP1 too btw
Earlier you showed the typedef

typedef unsigned int u32;

but in your code you have

1
2
3
4
5
i32 crap01 = 0; // Added crap01=0 and crap02=0 now cnrGoodModel and
i32 crap02 = 0; // cnrBadModel increment fine. Remove them and only one increments
i32 cnrGoodModel = 0;
i32 cnrBadModel = 0;
...


What is i32? If they are indeed unsigned then that could be the problem because statements like

--cnrGoodModel < 0

would never be true and you would wind up overstepping the bounds of the array. You should ensure that your array indices are signed integers in this case.
Topic archived. No new replies allowed.