2424#include < stack>
2525#include < unordered_set>
2626#include < ctime>
27+ #include < urlmon.h>
2728
2829#include < Psapi.h>
2930#include < shlwapi.h>
3031
32+ #pragma comment(lib, "urlmon.lib")
33+
3134using namespace plugin ;
3235
3336const int MAX_PED_ID = 300 ;
@@ -71,7 +74,7 @@ std::map<unsigned short, std::pair<CVector, float>> LightPositions;
7174std::map<unsigned short , rgba> LightColors;
7275std::map<unsigned short , rgba> LightColors2;
7376std::map<unsigned short , int > pedTimeSinceLastSpawned;
74- std::map<unsigned short , unsigned short > pedOriginalModels;
77+ std::map<unsigned short , std::vector< unsigned short > > pedOriginalModels;
7578std::map<unsigned short , std::array<std::vector<unsigned short >, 6 >> vehGroupWantedVariations;
7679std::map<unsigned short , std::string> wepVariationModels;
7780std::map<unsigned short , std::vector<unsigned short >> vehCurrentTuning;
@@ -86,13 +89,13 @@ std::set<unsigned short> vehMergeZones;
8689std::set<unsigned short > pedHasVariations;
8790std::set<unsigned short > vehHasVariations;
8891std::set<unsigned int > modifiedAddresses;
89- std::set<unsigned short > cloneRemoverIncludeVariations;
9092
9193std::stack<CPed*> pedStack;
9294std::stack<CVehicle*> vehStack;
9395std::stack<std::pair<CVehicle*, std::array<std::vector<unsigned short >, 17 >>> tuningStack;
9496// std::stack<std::pair<CVehicle*, std::array<int, 16>>> tuningStack;
9597
98+ std::vector<unsigned short > cloneRemoverIncludeVariations;
9699std::vector<unsigned short > cloneRemoverExclusions;
97100std::vector<unsigned short > pedCurrentVariations[MAX_PED_ID];
98101std::vector<unsigned short > vehCurrentVariations[212 ];
@@ -129,6 +132,8 @@ int spawnDelay = 3;
129132
130133bool keyDown = false ;
131134
135+ int timeUpdate = 8001 ;
136+
132137void getLoadedModules ()
133138{
134139 modulesSet.clear ();
@@ -146,6 +151,93 @@ void getLoadedModules()
146151 }
147152}
148153
154+ bool checkForUpdate ()
155+ {
156+ auto funcFail = []() {
157+ if (logfile.is_open ())
158+ logfile << " Check for updates failed." << std::endl;
159+
160+ return false ;
161+ };
162+
163+ IStream* stream;
164+
165+ if (URLOpenBlockingStream (0 , " http://api.github.com/repos/ViperJohnGR/ModelVariations/tags" , &stream, 0 , 0 ) != S_OK)
166+ return funcFail ();
167+
168+ std::string str (51 , 0 );
169+ if (stream->Read (&str[0 ], 50 , NULL ) != S_OK)
170+ return funcFail ();
171+
172+ stream->Release ();
173+ str = str.substr (11 , 10 );
174+ str.erase (str.find (' "' ));
175+
176+ const char *newV = str.c_str ();
177+ const char *oldV = MOD_VERSION;
178+
179+ return std::lexicographical_compare (oldV, oldV+strlen (oldV), newV, newV+strlen (newV));
180+ }
181+
182+ bool pedDelaySpawn (unsigned short model, bool includeParentModels)
183+ {
184+ if (!includeParentModels)
185+ {
186+ if (pedTimeSinceLastSpawned.find (model) != pedTimeSinceLastSpawned.end ())
187+ return true ;
188+ }
189+ else
190+ {
191+ auto it = pedOriginalModels.find (model);
192+ if (it != pedOriginalModels.end ())
193+ for (auto &i : it->second )
194+ if (pedTimeSinceLastSpawned.find (i) != pedTimeSinceLastSpawned.end ())
195+ return true ;
196+ }
197+ return false ;
198+ }
199+
200+ void insertPedSpawnedOriginalModels (unsigned short model)
201+ {
202+ auto it = pedOriginalModels.find (model);
203+ if (it != pedOriginalModels.end ())
204+ for (auto & i : it->second )
205+ pedTimeSinceLastSpawned.insert ({ i, clock () });
206+ }
207+
208+ bool compareOriginalModels (unsigned short model1, unsigned short model2)
209+ {
210+ if (model1 == model2)
211+ return true ;
212+
213+ auto it1 = pedOriginalModels.find (model1);
214+ auto it2 = pedOriginalModels.find (model2);
215+ if (it1 != pedOriginalModels.end () && it2 != pedOriginalModels.end ())
216+ return std::find_first_of (it1->second .begin (), it1->second .end (), it2->second .begin (), it2->second .end ()) != it1->second .end ();
217+ else
218+ {
219+ unsigned short model = 0 ;
220+ std::vector<unsigned short > *vec = NULL ;
221+ if (it1 != pedOriginalModels.end ())
222+ {
223+ model = model2;
224+ vec = &it1->second ;
225+ }
226+ else if (it2 != pedOriginalModels.end ())
227+ {
228+ model = model1;
229+ vec = &it2->second ;
230+ }
231+ else
232+ return false ;
233+
234+ if (std::find (vec->begin (), vec->end (), model) != vec->end ())
235+ return true ;
236+ }
237+
238+ return false ;
239+ }
240+
149241void filterWantedVariations (std::vector<unsigned short >& vec, std::vector<unsigned short >& wantedVec)
150242{
151243 bool matchFound = false ;
@@ -165,15 +257,6 @@ void filterWantedVariations(std::vector<unsigned short>& vec, std::vector<unsign
165257 vec = vec2;
166258}
167259
168- static unsigned short getVariationOriginalModel (unsigned short model)
169- {
170- auto it = pedOriginalModels.find (model);
171- if (it != pedOriginalModels.end ())
172- return it->second ;
173-
174- return model;
175- }
176-
177260bool IdExists (std::vector<unsigned short >& vec, int id)
178261{
179262 if (vec.size () < 1 )
@@ -187,7 +270,7 @@ bool IdExists(std::vector<unsigned short>& vec, int id)
187270
188271bool isValidPedId (int id)
189272{
190- if (id <= 0 && id >= MAX_PED_ID)
273+ if (id <= 0 || id >= MAX_PED_ID)
191274 return false ;
192275 if (id >= 190 && id <= 195 )
193276 return false ;
@@ -543,17 +626,22 @@ void loadIniData(bool firstTime)
543626
544627 for (unsigned int j = 0 ; j < 16 ; j++)
545628 for (unsigned int k = 0 ; k < pedVariations[i][j].size (); k++)
546- if (pedVariations[i][j][k] > 0 && pedVariations[i][j][k] < 32000 && pedVariations[i][j][k] != i)
547- pedOriginalModels.insert ({ pedVariations[i][j][k], i });
629+ if (pedVariations[i][j][k] > 0 && pedVariations[i][j][k] != i)
630+ {
631+ if (pedOriginalModels.find (pedVariations[i][j][k]) != pedOriginalModels.end ())
632+ pedOriginalModels[pedVariations[i][j][k]].push_back ((unsigned short )i);
633+ else
634+ pedOriginalModels.insert ({ pedVariations[i][j][k], {(unsigned short )i} });
635+ }
636+
637+ for (auto it : pedOriginalModels)
638+ std::sort (it.second .begin (), it.second .end ());
548639
549640 if (iniPed.ReadInteger (section, " MergeZonesWithCities" , 0 ) == 1 )
550641 pedMergeZones.insert ((unsigned short )i);
551642
552643 if (iniPed.ReadInteger (section, " DontInheritBehaviour" , 0 ) == 1 )
553644 dontInheritBehaviourModels.insert ((unsigned short )i);
554-
555- if (iniPed.ReadInteger (section, " CloneRemoverIncludeVariations" , 0 ) == 1 )
556- cloneRemoverIncludeVariations.insert ((unsigned short )i);
557645 }
558646 }
559647
@@ -568,6 +656,8 @@ void loadIniData(bool firstTime)
568656 wepVariationModels.insert ({ modelid, section });
569657 }
570658
659+ cloneRemoverIncludeVariations = iniPed.ReadLine (" Settings" , " CloneRemoverIncludeVariations" , READ_PEDS);
660+
571661 if (firstTime)
572662 {
573663 enableCloneRemover = iniPed.ReadInteger (" Settings" , " EnableCloneRemover" , 0 );
@@ -771,6 +861,9 @@ class ModelVariations {
771861
772862 Events::initRwEvent += []
773863 {
864+ // if (checkForUpdate())
865+ // MessageBox(NULL, "Model Variations: New version available!\nhttps://github.com/ViperJohnGR/ModelVariations", "Update available", MB_ICONINFORMATION);
866+
774867 loadIniData (true );
775868 installHooks ();
776869
@@ -804,6 +897,11 @@ class ModelVariations {
804897
805898 if (logfile.is_open ())
806899 getLoadedModules ();
900+
901+ if (checkForUpdate ())
902+ timeUpdate = clock ();
903+ else
904+ timeUpdate = -1 ;
807905 };
808906
809907 Events::processScriptsEvent += []
@@ -854,6 +952,11 @@ class ModelVariations {
854952
855953 Events::gameProcessEvent += []
856954 {
955+ if (timeUpdate > -1 && ((clock () - timeUpdate) / CLOCKS_PER_SEC > 6 ))
956+ {
957+ CMessages::AddMessageJumpQ ((char *)" ~y~Model Variations~s~: Update available." , 4000 , 0 , false );
958+ timeUpdate = -1 ;
959+ }
857960
858961 if (disableKey > 0 && KeyPressed (disableKey))
859962 {
@@ -1062,8 +1165,8 @@ class ModelVariations {
10621165
10631166 if (IsPedPointerValid (ped) && enableCloneRemover == 1 && ped->m_nCreatedBy != 2 && CPools::ms_pPedPool && pedRemoved == false ) // Clone remover
10641167 {
1065- bool includeVariations = cloneRemoverIncludeVariations.find ( ped->m_nModelIndex ) != cloneRemoverIncludeVariations.end ();
1066- if (pedTimeSinceLastSpawned. find ((includeVariations) ? getVariationOriginalModel ( ped->m_nModelIndex ) : ped-> m_nModelIndex ) != pedTimeSinceLastSpawned. end ( )) // Delete peds spawned before SpawnTime
1168+ bool includeVariations = std::find ( cloneRemoverIncludeVariations.begin (), cloneRemoverIncludeVariations. end (), ped->m_nModelIndex ) != cloneRemoverIncludeVariations.end ();
1169+ if (pedDelaySpawn ( ped->m_nModelIndex , includeVariations )) // Delete peds spawned before SpawnTime
10671170 {
10681171 if (!IsVehiclePointerValid (ped->m_pVehicle ))
10691172 {
@@ -1105,11 +1208,14 @@ class ModelVariations {
11051208
11061209 if (!pedRemoved && IsPedPointerValid (ped) && !IdExists (cloneRemoverExclusions, ped->m_nModelIndex ) && ped->m_nModelIndex > 0 ) // Delete peds already spawned
11071210 {
1108- pedTimeSinceLastSpawned.insert ({ ((includeVariations) ? getVariationOriginalModel (ped->m_nModelIndex ) : ped->m_nModelIndex ), clock () });
1211+ if (includeVariations)
1212+ insertPedSpawnedOriginalModels (ped->m_nModelIndex );
1213+ else
1214+ pedTimeSinceLastSpawned.insert ({ ped->m_nModelIndex , clock () });
1215+
11091216 for (CPed* ped2 : CPools::ms_pPedPool)
11101217 if ( IsPedPointerValid (ped2) && ped2 != ped && ((includeVariations) ?
1111- (getVariationOriginalModel (ped->m_nModelIndex ) == getVariationOriginalModel (ped2->m_nModelIndex )) :
1112- (ped->m_nModelIndex == ped2->m_nModelIndex )) )
1218+ (compareOriginalModels (ped->m_nModelIndex , ped2->m_nModelIndex )) : (ped->m_nModelIndex == ped2->m_nModelIndex )) )
11131219 {
11141220 if (!IsVehiclePointerValid (ped->m_pVehicle ))
11151221 {
0 commit comments