the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2
3#include "ItemStat.h"
4
5#include "Achievement.h"
6#include "Achievements.h"
7
8#include "DamageSource.h"
9#include "Player.h"
10#include "ItemInstance.h"
11#include "Tile.h"
12#include "Item.h"
13#include "Level.h"
14
15#include "..\Minecraft.Client\Minecraft.h"
16#include "LevelData.h"
17#include "LevelSettings.h"
18
19#include "..\Minecraft.Client\LocalPlayer.h"
20#include "..\Minecraft.Client\MultiPlayerLocalPlayer.h"
21
22#include "EntityIO.h"
23
24#include "..\Minecraft.Client\Durango\ServiceConfig\Events-XBLA.8-149E11AEEvents.h"
25
26#include "DurangoStats.h"
27
28 ///////////////////
29 // Ds Item Event //
30 ///////////////////
31
32string DsItemEvent::nameMethods[] = {
33 "NONE", "itemPickedUp", "itemCrafted",
34 "itemTakenFromChest", "itemTakenFromEnderchest",
35 "itemBought", "itemSmithed", "blockMined", "blockPlaced", "MAX"
36};
37
38DsItemEvent::DsItemEvent(int id, const wstring &name) : Stat(id,name) {}
39
40bool DsItemEvent::onLeaderboard(ELeaderboardId leaderboard, eAcquisitionMethod methodId, Param *param)
41{
42 switch (methodId)
43 {
44 case eAcquisitionMethod_Pickedup:
45 switch (param->itemId)
46 {
47 case Item::egg_Id:
48 case Tile::mushroom_brown_Id:
49 case Tile::mushroom_red_Id:
50 return leaderboard == eLeaderboardId_FARMING;
51 }
52 break;
53
54 case eAcquisitionMethod_Mined:
55 switch (param->itemId)
56 {
57 case Tile::dirt_Id:
58 case Tile::stoneBrick_Id:
59 case Tile::sand_Id:
60 case Tile::stone_Id:
61 case Tile::gravel_Id:
62 case Tile::clay_Id:
63 case Tile::obsidian_Id:
64 return leaderboard == eLeaderboardId_MINING;
65
66 case Tile::wheat_Id:
67 case Tile::pumpkin_Id:
68 case Tile::reeds_Id:
69 return leaderboard == eLeaderboardId_FARMING;
70 }
71 break;
72 }
73
74 return false;
75}
76
77
78// 4J-JEV, for tiles/items we want to record stats together.
79int DsItemEvent::mergeIds(int itemId)
80{
81 switch (itemId)
82 {
83 default:
84 return itemId;
85
86 case Tile::mushroom_brown_Id:
87 case Tile::mushroom_red_Id:
88 return Tile::mushroom_brown_Id;
89
90 case Tile::dirt_Id:
91 case Tile::grass_Id:
92 case Tile::farmland_Id:
93 return Tile::dirt_Id;
94
95 case Tile::redstoneLight_Id:
96 case Tile::redstoneLight_lit_Id:
97 return Tile::redstoneLight_Id;
98
99 case Tile::redStoneOre_Id:
100 case Tile::redStoneOre_lit_Id:
101 return Tile::redStoneOre_Id;
102 }
103}
104
105void DsItemEvent::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
106{
107 if (paramBlob.length == sizeof(Param))
108 {
109 Param *param = (Param *) paramBlob.data;
110
111 // Combine block ids.
112 param->itemId = mergeIds( param->itemId );
113
114 // Send farming leaderboard updates.
115 if ( (param->methodId == eAcquisitionMethod_Pickedup && onLeaderboard(eLeaderboardId_FARMING, eAcquisitionMethod_Pickedup, param))
116 || (param->methodId == eAcquisitionMethod_Mined && onLeaderboard(eLeaderboardId_FARMING, eAcquisitionMethod_Mined, param)) )
117 {
118 EventWriteLeaderboardTotals(
119 DurangoStats::getUserId(player), //UserId
120 DurangoStats::getPlayerSession(), // PlayerSessionId
121 player->level->difficulty, // Difficulty,
122 eLeaderboardId_FARMING, // ScoreboardId
123 param->itemCount);
124
125 app.DebugPrintf("<%ls>\tscoreboardFarming(%i:%i:%i)\n", DurangoStats::getUserId(player),
126 player->level->difficulty, eLeaderboardId_FARMING, param->itemCount);
127 }
128
129 // Send mining leaderboard updates.
130 if ( param->methodId == eAcquisitionMethod_Mined && onLeaderboard(eLeaderboardId_MINING, eAcquisitionMethod_Mined, param) )
131 {
132 EventWriteLeaderboardTotals(
133 DurangoStats::getUserId(player), //UserId
134 DurangoStats::getPlayerSession(), // PlayerSessionId
135 player->level->difficulty, // Difficulty,
136 eLeaderboardId_MINING, // ScoreboardId
137 param->itemCount);
138 app.DebugPrintf("<%ls>\tscoreboardMining(%i:%i:%i)\n", DurangoStats::getUserId(player),
139 player->level->difficulty, eLeaderboardId_MINING, param->itemCount);
140 }
141
142 // Debug printout.
143 string method = nameMethods[(int)param->methodId];
144 app.DebugPrintf("<%ls>\t%s(%i:%i:%i)\n", DurangoStats::getUserId(player),
145 method.c_str(), param->itemId, param->itemAux, param->itemCount);
146
147 // Split on acquisition method, then send relevant events.
148 if (param->methodId == eAcquisitionMethod_Placed)
149 {
150 EventWriteBlockPlaced(
151 DurangoStats::getUserId(player),
152 DurangoStats::getPlayerSession(),
153 player->level->difficulty,
154 param->itemId,
155 param->itemAux,
156 param->itemCount
157 );
158 }
159 else if (param->methodId == eAcquisitionMethod_Mined)
160 {
161 EventWriteBlockBroken(
162 DurangoStats::getUserId(player),
163 DurangoStats::getPlayerSession(),
164 player->level->difficulty,
165 param->itemId,
166 param->itemAux,
167 param->itemCount
168 );
169 }
170 else
171 {
172 EventWriteMcItemAcquired(
173 DurangoStats::getUserId(player),
174 0, // TODO
175 DurangoStats::getPlayerSession(),
176 0,
177 0,
178 player->level->difficulty,
179 param->itemId,
180 param->methodId,
181 0, 0, 0, // (x,y,z)
182 param->itemAux,
183 param->itemCount
184 );
185 }
186 }
187}
188
189/* 4J-JEV: note that mined events will only fire with 'Instant_Mine' on if you are carrying an appropriate
190 * tool for the block that you are mining.
191 */
192byteArray DsItemEvent::createParamBlob(eAcquisitionMethod eMethod, int itemId, int itemAux, int itemCount)
193{
194 byteArray output;
195 Param param = { eMethod, itemId, itemAux, itemCount };
196 output.data = (byte *) new Param(param);
197 output.length = sizeof(Param);
198 return output;
199}
200
201
202 ///////////////////
203 // Ds Mob Killed //
204 ///////////////////
205
206DsMobKilled::DsMobKilled(int id, const wstring &name) : Stat(id,name) {}
207
208void DsMobKilled::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
209{
210 if (paramBlob.length == sizeof(Param))
211 {
212 Param *param = (Param *) paramBlob.data;
213
214 if (param->mobType < 0) return;
215
216 if (EventWriteMobKilled(DurangoStats::getUserId(player),
217 0,
218 DurangoStats::getPlayerSession(),
219 DurangoStats::getMultiplayerCorrelationId(),
220 0,
221 player->level->difficulty,
222 DurangoStats::getPlayerSession(), // ROUND ID
223 0,
224 param->weaponId,
225 param->mobType,
226 param->isRanged?1:0,
227 0, 0, 0, // (x,y,z),
228 0,
229 param->distance,
230 param->mobType)
231 == 0)
232 {
233 app.DebugPrintf("<%ls>\t%s(%i:%i:%i:%i)\n", DurangoStats::getUserId(player),
234 (param->isRanged?"mobShotWithEntity":"mobKilledInMelee"),
235 param->mobType, param->weaponId, param->distance, param->damage);
236 }
237
238 switch(EntityIO::getClass(param->mobType))
239 {
240 case eTYPE_MONSTER:
241 if(param->mobType != SPIDER_JOCKEY_ID) break;
242 // Fallthrough is spider jockey
243 case eTYPE_ZOMBIE:
244 case eTYPE_SKELETON:
245 case eTYPE_CREEPER:
246 case eTYPE_SPIDER:
247 case eTYPE_PIGZOMBIE:
248 case eTYPE_SLIME:
249
250 if (EventWriteLeaderboardTotals(
251 DurangoStats::getUserId(player), //UserId
252 DurangoStats::getPlayerSession(), // PlayerSessionId
253 player->level->difficulty, // Difficulty,
254 eLeaderboardId_KILLING, // ScoreboardId
255 1) // Count
256 == 0)
257 {
258 app.DebugPrintf("<%ls>\tscoreboardKills(%i:%i:1)\n", DurangoStats::getUserId(player),
259 player->level->difficulty, eLeaderboardId_KILLING);
260 }
261 }
262 }
263}
264
265byteArray DsMobKilled::createParamBlob(shared_ptr<Player> player, shared_ptr<Mob> mob, DamageSource *dmgSrc)
266{
267 // 4J-JEV: Get the id we use for Durango Server Stats.
268 int mob_networking_id;
269 eINSTANCEOF mobEType = mob->GetType();
270 if ( (mobEType == eTYPE_SPIDER) && (mob->rider.lock() != NULL) && (mob->rider.lock()->GetType() == eTYPE_SKELETON) && mob->rider.lock()->isAlive() )
271 {
272 mob_networking_id = SPIDER_JOCKEY_ID; // Spider jockey only a concept for leaderboards.
273 }
274 else if ( (mobEType == eTYPE_SKELETON) && (mob->riding != NULL) && (mob->riding->GetType() == eTYPE_SPIDER) && mob->riding->isAlive() )
275 {
276 mob_networking_id = SPIDER_JOCKEY_ID; // Spider jockey only a concept for leaderboards.
277 }
278 else
279 {
280 mob_networking_id = EntityIO::eTypeToIoid(mobEType);
281 }
282
283 // Kill made with projectile, arrow/ghast/fireball/snowball.
284 // NB: Snowball kills would make an awesome achievement. ("Not a snowball's chance...")
285 if ( dmgSrc->isProjectile() )
286 {
287 byteArray output;
288 Param param = {
289 DsMobKilled::RANGED,
290 mob_networking_id,
291 EntityIO::eTypeToIoid(dmgSrc->getDirectEntity()->GetType()),
292 mob->distanceTo(player->x, player->y, player->z),
293 0/*not needed*/
294 };
295 output.data = (byte*) new Param(param);
296 output.length = sizeof(Param);
297 return output;
298 }
299
300 // Kill made in melee, use itemInHand as weapon.
301 shared_ptr<ItemInstance> item = player->getCarriedItem();
302 byteArray output;
303 Param param = {
304 DsMobKilled::MELEE,
305 mob_networking_id,
306 (item != NULL ? item->getItem()->id : 0),
307 mob->distanceTo(player->x, player->y, player->z),
308 0/*not needed*/
309 };
310 output.data = (byte*) new Param(param);
311 output.length = sizeof(Param);
312 return output;
313}
314
315
316 /////////////////////
317 // Ds Mob Interact //
318 /////////////////////
319
320string DsMobInteract::nameInteract[] = {
321 "unknownMobInteraction", "mobBred", "mobTamed", "mobCured", "mobCrafted", "mobSheared"
322};
323
324DsMobInteract::DsMobInteract(int id, const wstring &name) : Stat(id,name) {}
325
326void DsMobInteract::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
327{
328 if (paramBlob.length == sizeof(Param))
329 {
330 Param *param = (Param *) paramBlob.data;
331
332 if (param->mobId < 0) return;
333
334 app.DebugPrintf("<%ls>\t%s(%i)\n", DurangoStats::getUserId(player),
335 nameInteract[param->interactionType].c_str(), param->mobId);
336
337 EventWriteMobInteract(
338 DurangoStats::getUserId(player),
339 DurangoStats::getPlayerSession(),
340 param->mobId,
341 param->interactionType );
342 }
343}
344
345byteArray DsMobInteract::createParamBlob(eInteract interactionId, int entityId)
346{
347 byteArray output;
348 Param param = { interactionId, EntityIO::eTypeToIoid((eINSTANCEOF)entityId) };
349 output.data = (byte*) new Param(param);
350 output.length = sizeof(Param);
351 return output;
352}
353
354
355 ///////////////
356 // Ds Travel //
357 ///////////////
358
359string DsTravel::nameMethods[eMethod_MAX] =
360 {
361 "Walk", "Swim", "Fall", "Climb", "Cart", "Boat", "Pig", "Time"
362 };
363
364unsigned int DsTravel::CACHE_SIZES[eMethod_MAX] =
365 {
366 40, // WALK - Meters?
367 20, // SWIM - Meters?
368 0, // FALL - Meters? - Fall event naturally only sends on land, no caching necessary.
369 10, // CLIMB - Meters?
370 70, // CART - Meters?
371 70, // BOAT - Meters?
372 10, // PIG - Meters?
373 20*60*5, // TIME - GameTicks (20*60*5 ~ 5 mins)
374 };
375
376DsTravel::DsTravel(int id, const wstring &name) : Stat(id,name)
377{
378 ZeroMemory(¶m_cache, sizeof(unsigned int)*eMethod_MAX*MAX_LOCAL_PLAYERS);
379}
380
381void DsTravel::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
382{
383 if (paramBlob.length == sizeof(Param))
384 {
385 Param *param = (Param*) paramBlob.data;
386
387 int newDistance = cache(player->GetXboxPad(), *param);
388
389 if ( newDistance > 0 ) write(player, param->method, newDistance);
390 }
391}
392
393byteArray DsTravel::createParamBlob(eMethod method, int distance)
394{
395 byteArray output;
396 Param param = { method, distance };
397 output.data = (byte*) new Param(param);
398 output.length = sizeof(Param);
399 return output;
400}
401
402int DsTravel::cache(int iPad, Param ¶m)
403{
404 if ( (eMethod_walk <= param.method) && (param.method < eMethod_MAX) )
405 {
406 param_cache[iPad][param.method] += param.distance;
407
408 if (param_cache[iPad][param.method] > CACHE_SIZES[param.method])
409 {
410 int out = param_cache[iPad][param.method];
411 param_cache[iPad][param.method] = 0;
412 return out;
413 }
414 }
415
416 return 0;
417}
418
419void DsTravel::flush(shared_ptr<LocalPlayer> player)
420{
421 int iPad = player->GetXboxPad();
422 for (int i = 0; i < eMethod_MAX; i++)
423 {
424 if (param_cache[iPad][i] > 0)
425 {
426 write( player, (eMethod) i, param_cache[iPad][i] );
427 param_cache[iPad][i] = 0;
428 }
429 }
430}
431
432void DsTravel::write(shared_ptr<LocalPlayer> player, eMethod method, int distance)
433{
434 if (player == nullptr) return;
435
436 app.DebugPrintf("<%ls>\t%s(%i)\n", DurangoStats::getUserId(player), nameMethods[method].c_str(), distance);
437
438 if (method == DsTravel::eMethod_time)
439 {
440 EventWriteIncTimePlayed(
441 DurangoStats::getUserId(player),
442 DurangoStats::getPlayerSession(),
443 player->level->difficulty,
444 distance
445 );
446 }
447 else if ( (eMethod_walk <= method) && (method < eMethod_MAX) )
448 {
449 EventWriteIncDistanceTravelled(
450 DurangoStats::getUserId(player),
451 DurangoStats::getPlayerSession(),
452 player->level->difficulty,
453 distance,
454 method
455 );
456
457 switch(method)
458 {
459 case eMethod_walk:
460 case eMethod_fall:
461 case eMethod_minecart:
462 case eMethod_boat:
463 EventWriteLeaderboardTotals(
464 DurangoStats::getUserId(player), //UserId
465 DurangoStats::getPlayerSession(), // PlayerSessionId
466 player->level->difficulty, // Difficulty,
467 eLeaderboardId_TRAVELLING, // ScoreboardId
468 distance);
469 break;
470 }
471 }
472}
473
474 //////////////////
475 // Ds Item Used //
476 //////////////////
477
478DsItemUsed::DsItemUsed(int id, const wstring &name) : Stat(id,name) {}
479
480void DsItemUsed::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
481{
482 if (paramBlob.length == sizeof(Param))
483 {
484 Param *param = (Param*) paramBlob.data;
485 app.DebugPrintf("<%ls>\titemUsed(%i,%i,%i)\n", DurangoStats::getUserId(player),
486 param->itemId,
487 param->aux,
488 param->count
489 );
490
491 EventWriteMcItemUsed(
492 DurangoStats::getUserId(player),
493 0, // SectionId,
494 DurangoStats::getPlayerSession(),
495 0, // MultiplayerCorrelationId,
496 0, // Gameplay Mode,
497 player->level->difficulty,
498 param->itemId,
499 0, 0, 0, // (x,y,z)
500 param->aux,
501 param->count,
502 param->hunger
503 );
504 }
505}
506
507byteArray DsItemUsed::createParamBlob(int itemId, int aux, int count, int health, int hunger)
508{
509 byteArray output;
510 Param param = { itemId, aux, count, health, hunger };
511 output.data = (byte*) new Param(param);
512 output.length = sizeof(Param);
513 return output;
514}
515
516
517 ////////////////////
518 // Ds Achievement //
519 ////////////////////
520
521DsAchievement::DsAchievement(int id, const wstring &name) : Stat(id,name) {}
522
523void DsAchievement::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
524{
525 if (paramBlob.length == sizeof(SmallParam))
526 {
527 SmallParam *paramS = (SmallParam*) paramBlob.data;
528 assert( DurangoStats::binaryAchievement(paramS->award) );
529 app.DebugPrintf("<%ls>\tAchievement(%i)\n", DurangoStats::getUserId(player), paramS->award);
530
531 bool canAward = true;
532 if(paramS->award == eAward_stayinFrosty)
533 {
534 canAward = !player->m_bHasAwardedStayinFrosty;
535 player->m_bHasAwardedStayinFrosty = true;
536 }
537
538 if(canAward)
539 {
540 EventWriteAchievementGet(
541 DurangoStats::getUserId(player),
542 DurangoStats::getPlayerSession(),
543 paramS->award
544 );
545 }
546 }
547 else if (paramBlob.length == sizeof(LargeParam))
548 {
549 LargeParam *paramL = (LargeParam*) paramBlob.data;
550 assert( DurangoStats::enhancedAchievement(paramL->award) );
551
552 switch(paramL->award)
553 {
554 case eAward_musicToMyEars:
555 app.DebugPrintf("<%ls>\tmusicToMyEars(%i)\n", DurangoStats::getUserId(player), paramL->count);
556 EventWritePlayedMusicDisc(
557 DurangoStats::getUserId(player),
558 DurangoStats::getPlayerSession(),
559 paramL->count
560 );
561 break;
562
563 case eAward_chestfulOfCobblestone:
564 app.DebugPrintf("<%ls>\tchestfulOfCobblestone(%i)\n", DurangoStats::getUserId(player), paramL->count);
565 EventWriteChestfulOfCobblestone(
566 DurangoStats::getUserId(player),
567 DurangoStats::getPlayerSession(),
568 paramL->count
569 );
570 break;
571
572 case eAward_overkill:
573 app.DebugPrintf("<%ls>\toverkill(%i)\n", DurangoStats::getUserId(player), paramL->count);
574 EventWriteOverkill(
575 DurangoStats::getUserId(player),
576 DurangoStats::getPlayerSession(),
577 paramL->count
578 );
579 break;
580
581 case eAward_OnARail:
582 app.DebugPrintf("<%ls>\nonARail(%i)\n", DurangoStats::getUserId(player), paramL->count);
583 EventWriteOnARail(
584 DurangoStats::getUserId(player),
585 DurangoStats::getPlayerSession(),
586 paramL->count
587 );
588 break;
589 }
590 }
591 else assert(false); // Unsuitable paramBlob length.
592}
593
594byteArray DsAchievement::createSmallParamBlob(eAward award)
595{
596 byteArray output;
597 SmallParam param = { award };
598 output.data = (byte*) new SmallParam(param);
599 output.length = sizeof(SmallParam);
600 return output;
601}
602
603byteArray DsAchievement::createLargeParamBlob(eAward award, int count)
604{
605 byteArray output;
606 LargeParam param = { award, count };
607 output.data = (byte*) new LargeParam(param);
608 output.length = sizeof(LargeParam);
609 return output;
610}
611
612
613 //////////////////////////
614 // Ds Changed Dimension //
615 //////////////////////////
616
617DsChangedDimension::DsChangedDimension(int id, const wstring &name) : Stat(id,name) {}
618
619void DsChangedDimension::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
620{
621 if (paramBlob.length == sizeof(Param))
622 {
623 Param *param = (Param*) paramBlob.data;
624 app.DebugPrintf("<%ls>\tchangedDimension(%i:%i)\n", DurangoStats::getUserId(player),
625 param->fromDimId, param->toDimId);
626
627 // No longer used.
628 }
629}
630
631byteArray DsChangedDimension::createParamBlob(int fromDimId, int toDimId)
632{
633 byteArray output;
634 Param param = { fromDimId, toDimId };
635 output.data = (byte*) new Param(param);
636 output.length = sizeof(Param);
637 return output;
638}
639
640
641 //////////////////////
642 // Ds Entered Biome //
643 //////////////////////
644
645DsEnteredBiome::DsEnteredBiome(int id, const wstring &name) : Stat(id,name) {}
646
647void DsEnteredBiome::handleParamBlob(shared_ptr<LocalPlayer> player, byteArray paramBlob)
648{
649 if (paramBlob.length == sizeof(Param))
650 {
651 Param *param = (Param*) paramBlob.data;
652 app.DebugPrintf("<%ls>\tenteredBiome(%i)\n", DurangoStats::getUserId(player), param->biomeId);
653
654 EventWriteEnteredNewBiome(
655 DurangoStats::getUserId(player),
656 DurangoStats::getPlayerSession(),
657 param->biomeId
658 );
659 }
660}
661
662byteArray DsEnteredBiome::createParamBlob(int biomeId)
663{
664 byteArray output;
665 Param param = { biomeId };
666 output.data = (byte*) new Param(param);
667 output.length = sizeof(Param);
668 return output;
669}
670
671 ////////////////////////
672 // DURANGO STATISTICS //
673 ////////////////////////
674
675DurangoStats::DurangoStats()
676{
677 // Hopefully only using the first parameter
678 itemsAcquired = new DsItemEvent( itemsAcquired_Id, L"itemsAcquired" );
679 itemsAcquired->postConstruct();
680
681 itemUsed = new DsItemUsed( itemUsed_Id, L"itemUsed" );
682 itemUsed->postConstruct();
683
684 travel = new DsTravel( travel_Id, L"travel" );
685 travel->setAwardLocallyOnly()->postConstruct();
686
687 mobKilled = new DsMobKilled( mobKilled_Id, L"mobKilled" );
688 mobKilled->postConstruct();
689
690 mobInteract = new DsMobInteract( mobInteract_Id, L"mobInteract" );
691 mobInteract->postConstruct();
692
693 changedDimension = new DsChangedDimension( changedDimension_Id, L"changedDimension" );
694 changedDimension->postConstruct();
695
696 enteredBiome = new DsEnteredBiome( enteredBiome_Id, L"enteredBiome" );
697 enteredBiome->postConstruct();
698
699 achievement = new DsAchievement( binAchievement_Id, L"achievement" );
700 achievement->postConstruct();
701
702 achievementLocal = new DsAchievement( binAchievementLocal_Id, L"achievementLocal" );
703 achievementLocal->setAwardLocallyOnly();
704 achievementLocal->postConstruct();
705
706 EventRegisterXBLA_149E11AE();
707}
708
709DurangoStats::~DurangoStats()
710{
711 EventUnregisterXBLA_149E11AE();
712}
713
714Stat *DurangoStats::get_stat(int i)
715{
716 switch (i)
717 {
718 case itemsAcquired_Id: return (Stat*) itemsAcquired;
719 case itemUsed_Id: return (Stat*) itemUsed;
720 case travel_Id: return (Stat*) travel;
721 case mobKilled_Id: return (Stat*) mobKilled;
722 case mobInteract_Id: return (Stat*) mobInteract;
723 case changedDimension_Id: return (Stat*) changedDimension;
724 case enteredBiome_Id: return (Stat*) enteredBiome;
725 case binAchievement_Id: return (Stat*) achievement;
726 case binAchievementLocal_Id: return (Stat*) achievementLocal;
727
728 // Unrecognised stat id
729 default: assert(false); break;
730 }
731
732 return NULL;
733}
734
735Stat* DurangoStats::get_walkOneM()
736{
737 return travel;
738}
739
740Stat* DurangoStats::get_swimOneM()
741{
742 return travel;
743}
744
745Stat* DurangoStats::get_fallOneM()
746{
747 return travel;
748}
749
750Stat* DurangoStats::get_climbOneM()
751{
752 return travel;
753}
754
755Stat* DurangoStats::get_minecartOneM()
756{
757 return travel;
758}
759
760Stat* DurangoStats::get_boatOneM()
761{
762 return travel;
763}
764
765Stat* DurangoStats::get_pigOneM()
766{
767 return travel;
768}
769
770Stat *DurangoStats::get_cowsMilked()
771{
772 return get_itemsCrafted(Item::bucket_milk_Id);
773}
774
775Stat* DurangoStats::get_killMob()
776{
777 return mobKilled;
778}
779
780Stat* DurangoStats::get_breedEntity(eINSTANCEOF entityId)
781{
782 return mobInteract;
783}
784
785Stat* DurangoStats::get_tamedEntity(eINSTANCEOF entityId)
786{
787 return mobInteract;
788}
789
790Stat* DurangoStats::get_curedEntity(eINSTANCEOF entityId)
791{
792 return mobInteract;
793}
794
795Stat* DurangoStats::get_craftedEntity(eINSTANCEOF entityId)
796{
797 return mobInteract;
798}
799
800Stat* DurangoStats::get_shearedEntity(eINSTANCEOF entityId)
801{
802 return mobInteract;
803}
804
805Stat* DurangoStats::get_timePlayed()
806{
807 return travel;
808}
809
810Stat* DurangoStats::get_blocksPlaced(int blockId)
811{
812 return (Stat*) itemsAcquired;
813}
814
815Stat* DurangoStats::get_blocksMined(int blockId)
816{
817 return (Stat*) itemsAcquired;
818}
819
820Stat* DurangoStats::get_itemsCollected(int itemId, int itemAux)
821{
822 return (Stat*) itemsAcquired;
823}
824
825Stat* DurangoStats::get_itemsCrafted(int itemId)
826{
827 switch (itemId)
828 {
829 // 4J-JEV: These items can be crafted trivially to and from their block equivalents,
830 // 'Acquire Hardware' also relies on 'Count_Crafted(IronIngot) == Count_Forged(IronIngot)" on the Stats server.
831 case Item::ironIngot_Id:
832 case Item::goldIngot_Id:
833 case Item::diamond_Id:
834 case Item::redStone_Id:
835 case Item::emerald_Id:
836 return NULL;
837
838 case Item::dye_powder_Id:
839 default:
840 return (Stat*) itemsAcquired;
841 }
842
843}
844
845Stat* DurangoStats::get_itemsSmelted(int itemId)
846{
847 // 4J-JEV: Context needed for itemCrafted for iron/gold being smelted.
848 return (Stat*) itemsAcquired;
849}
850
851Stat* DurangoStats::get_itemsUsed(int itemId)
852{
853 return (Stat*) itemUsed;
854}
855
856Stat *DurangoStats::get_itemsBought(int itemId)
857{
858 return (Stat*) itemsAcquired;
859}
860
861Stat* DurangoStats::get_changedDimension(int from, int to)
862{
863 return (Stat*) changedDimension;
864}
865
866Stat* DurangoStats::get_enteredBiome(int biomeId)
867{
868 return (Stat*) enteredBiome;
869}
870
871Stat* DurangoStats::get_achievement(eAward achievementId)
872{
873 // Special case for 'binary' achievements.
874 if ( binaryAchievement(achievementId)
875 || enhancedAchievement(achievementId) )
876 {
877 switch (achievementId)
878 {
879 case eAward_chestfulOfCobblestone:
880 case eAward_TakingInventory:
881 return achievementLocal;
882
883 default:
884 return achievement;
885 }
886 }
887 else if (achievementId == eAward_zombieDoctor)
888 {
889 return get_curedEntity(eTYPE_ZOMBIE);
890 }
891
892 // Other achievements awarded through more detailed generic events.
893 return NULL;
894}
895
896byteArray DurangoStats::getParam_walkOneM(int distance)
897{
898 return DsTravel::createParamBlob(DsTravel::eMethod_walk, distance);
899}
900
901byteArray DurangoStats::getParam_swimOneM(int distance)
902{
903 return DsTravel::createParamBlob(DsTravel::eMethod_swim,distance);
904}
905
906byteArray DurangoStats::getParam_fallOneM(int distance)
907{
908 return DsTravel::createParamBlob(DsTravel::eMethod_fall,distance);
909}
910
911byteArray DurangoStats::getParam_climbOneM(int distance)
912{
913 return DsTravel::createParamBlob(DsTravel::eMethod_climb,distance);
914}
915
916byteArray DurangoStats::getParam_minecartOneM(int distance)
917{
918 return DsTravel::createParamBlob(DsTravel::eMethod_minecart,distance);
919}
920
921byteArray DurangoStats::getParam_boatOneM(int distance)
922{
923 return DsTravel::createParamBlob(DsTravel::eMethod_boat,distance);
924}
925
926byteArray DurangoStats::getParam_pigOneM(int distance)
927{
928 return DsTravel::createParamBlob(DsTravel::eMethod_pig,distance);
929}
930
931byteArray DurangoStats::getParam_cowsMilked()
932{
933 return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Crafted, Item::bucket_milk_Id, 0, 1);
934}
935
936byteArray DurangoStats::getParam_blocksPlaced(int blockId, int data, int count)
937{
938 return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Placed, blockId, data, count);
939}
940
941byteArray DurangoStats::getParam_blocksMined(int blockId, int data, int count)
942{
943 return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Mined, blockId, data, count);
944}
945
946byteArray DurangoStats::getParam_itemsCollected(int id, int aux, int count)
947{
948 return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Pickedup, id, aux, count);
949}
950
951byteArray DurangoStats::getParam_itemsCrafted(int id, int aux, int count)
952{
953 return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Crafted, id, aux, count);
954}
955
956byteArray DurangoStats::getParam_itemsUsed(shared_ptr<Player> player, shared_ptr<ItemInstance> itm)
957{
958 return DsItemUsed::createParamBlob(
959 itm->getItem()->id, itm->getAuxValue(), itm->GetCount(),
960 player->getHealth(), player->getFoodData()->getFoodLevel()
961 );
962}
963
964byteArray DurangoStats::getParam_itemsBought(int id, int aux, int count)
965{
966 return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Bought, id, aux, count);
967}
968
969byteArray DurangoStats::getParam_mobKill(shared_ptr<Player> player, shared_ptr<Mob> mob, DamageSource *dmgSrc)
970{
971 return DsMobKilled::createParamBlob(player,mob,dmgSrc);
972}
973
974byteArray DurangoStats::getParam_breedEntity(eINSTANCEOF entityId)
975{
976 return DsMobInteract::createParamBlob(DsMobInteract::eInteract_Breed, entityId);
977}
978
979byteArray DurangoStats::getParam_tamedEntity(eINSTANCEOF entityId)
980{
981 return DsMobInteract::createParamBlob(DsMobInteract::eInteract_Tamed, entityId);
982}
983
984byteArray DurangoStats::getParam_curedEntity(eINSTANCEOF entityId)
985{
986 return DsMobInteract::createParamBlob(DsMobInteract::eInteract_Cured, entityId);
987}
988
989byteArray DurangoStats::getParam_craftedEntity(eINSTANCEOF entityId)
990{
991 return DsMobInteract::createParamBlob(DsMobInteract::eInteract_Crafted, entityId);
992}
993
994byteArray DurangoStats::getParam_shearedEntity(eINSTANCEOF entityId)
995{
996 return DsMobInteract::createParamBlob(DsMobInteract::eInteract_Sheared, entityId);
997}
998
999byteArray DurangoStats::getParam_time(int timediff)
1000{
1001 return DsTravel::createParamBlob(DsTravel::eMethod_time, timediff);
1002}
1003
1004byteArray DurangoStats::getParam_changedDimension(int from, int to)
1005{
1006 return DsChangedDimension::createParamBlob(from,to);
1007}
1008
1009byteArray DurangoStats::getParam_enteredBiome(int biomeId)
1010{
1011 return DsEnteredBiome::createParamBlob(biomeId);
1012}
1013
1014byteArray DurangoStats::getParam_achievement(eAward id)
1015{
1016 if (binaryAchievement(id))
1017 {
1018 return DsAchievement::createSmallParamBlob(id);
1019 }
1020 else if (enhancedAchievement(id))
1021 {
1022 assert(false); // Should be calling the appropriate getParam function.
1023 }
1024 else if (id == eAward_zombieDoctor)
1025 {
1026 return getParam_curedEntity(eTYPE_ZOMBIE);
1027 }
1028
1029 // If its not a binary achievement,
1030 // don't bother constructing the param blob.
1031 return getParam_noArgs();
1032}
1033
1034byteArray DurangoStats::getParam_onARail(int dist)
1035{
1036 return DsAchievement::createLargeParamBlob(eAward_OnARail, dist);
1037}
1038
1039byteArray DurangoStats::getParam_chestfulOfCobblestone(int count)
1040{
1041 return DsAchievement::createLargeParamBlob(eAward_chestfulOfCobblestone, count);
1042}
1043
1044byteArray DurangoStats::getParam_overkill(int dmg)
1045{
1046 return DsAchievement::createLargeParamBlob(eAward_overkill, dmg);
1047}
1048
1049byteArray DurangoStats::getParam_musicToMyEars(int recordId)
1050{
1051 return DsAchievement::createLargeParamBlob(eAward_musicToMyEars, recordId);
1052}
1053
1054bool DurangoStats::binaryAchievement(eAward achievementId)
1055{
1056 switch (achievementId)
1057 {
1058 case eAward_InToTheNether:
1059 case eAward_theEnd:
1060 case eAward_WhenPigsFly:
1061 case eAward_diamondsToYou:
1062 case eAward_stayinFrosty:
1063 case eAward_renewableEnergy:
1064 case eAward_ironMan:
1065 case eAward_winGame:
1066 case /*maybe*/ eAward_TakingInventory:
1067 return true;
1068 default:
1069 return false;
1070 }
1071}
1072
1073/** 4J-JEV,
1074 Basically achievements with an inconsequential extra parameter
1075 that I thought best not to / prefered not to / couldn't be bothered to make class handlers for.
1076 (Motivation: it would be nice for players to see how close they were/are to achieving these things).
1077*/
1078bool DurangoStats::enhancedAchievement(eAward achievementId)
1079{
1080 switch (achievementId)
1081 {
1082 //case eAward_TakingInventory:
1083 case eAward_musicToMyEars:
1084 case eAward_chestfulOfCobblestone:
1085 case eAward_overkill:
1086 case eAward_OnARail:
1087 return true;
1088 default:
1089 return false;
1090 }
1091}
1092
1093
1094void DurangoStats::generatePlayerSession()
1095{
1096 DurangoStats *dsInstance = (DurangoStats *) GenericStats::getInstance();
1097 CoCreateGuid( &dsInstance->playerSessionId );
1098}
1099
1100LPCGUID DurangoStats::getPlayerSession()
1101{
1102 DurangoStats *dsInstance = (DurangoStats *) GenericStats::getInstance();
1103 LPCGUID lpcguid = &dsInstance->playerSessionId;
1104 return lpcguid;
1105}
1106
1107void DurangoStats::setMultiplayerCorrelationId(Platform::String^ mcpId)
1108{
1109 ((DurangoStats*)GenericStats::getInstance())->multiplayerCorrelationId = mcpId;
1110}
1111
1112LPCWSTR DurangoStats::getMultiplayerCorrelationId()
1113{
1114 return ((DurangoStats*)GenericStats::getInstance())->multiplayerCorrelationId->Data();
1115}
1116
1117LPCWSTR DurangoStats::getUserId(shared_ptr<LocalPlayer> player)
1118{
1119 return getUserId(player->GetXboxPad());
1120}
1121
1122LPCWSTR DurangoStats::getUserId(int iPad)
1123{
1124 static wstring cache = L"";
1125 PlayerUID uid = INVALID_XUID;
1126 ProfileManager.GetXUID(iPad, &uid, true);
1127 cache = uid.toString();
1128 return cache.c_str();
1129}
1130
1131void DurangoStats::playerSessionStart(PlayerUID uid, shared_ptr<Player> plr)
1132{
1133 if (plr != NULL && plr->level != NULL && plr->level->getLevelData() != NULL)
1134 {
1135 //wprintf(uid.toString().c_str());
1136
1137 //EventWritePlayerSessionStart(
1138 app.DebugPrintf(">>>\tPlayerSessionStart(%ls,%s,%ls,%i,%i)\n",
1139 uid.toString(),
1140 DurangoStats::getPlayerSession(),
1141 DurangoStats::getMultiplayerCorrelationId(),
1142 plr->level->getLevelData()->getGameType()->isSurvival(),
1143 plr->level->difficulty
1144 );
1145
1146 EventWritePlayerSessionStart(
1147 uid.toString().c_str(),
1148 DurangoStats::getPlayerSession(),
1149 DurangoStats::getMultiplayerCorrelationId(),
1150 plr->level->getLevelData()->getGameType()->isSurvival(),
1151 plr->level->difficulty
1152 );
1153 }
1154}
1155
1156void DurangoStats::playerSessionStart(int iPad)
1157{
1158 PlayerUID puid; shared_ptr<Player> plr;
1159 ProfileManager.GetXUID(iPad, &puid, true);
1160 plr = Minecraft::GetInstance()->localplayers[iPad];
1161 playerSessionStart(puid,plr);
1162}
1163
1164void DurangoStats::playerSessionPause(int iPad)
1165{
1166 shared_ptr<MultiplayerLocalPlayer> plr = Minecraft::GetInstance()->localplayers[iPad];
1167 if (plr != NULL && plr->level != NULL && plr->level->getLevelData() != NULL)
1168 {
1169 PlayerUID puid;
1170 ProfileManager.GetXUID(iPad, &puid, true);
1171
1172 //EventWritePlayerSessionPause(
1173 app.DebugPrintf(">>>\tPlayerSessionPause(%ls,%s,%ls)\n",
1174 puid.toString().c_str(),
1175 DurangoStats::getPlayerSession(),
1176 DurangoStats::getMultiplayerCorrelationId()
1177 );
1178
1179 EventWritePlayerSessionPause(
1180 puid.toString().c_str(),
1181 DurangoStats::getPlayerSession(),
1182 DurangoStats::getMultiplayerCorrelationId()
1183 );
1184 }
1185}
1186
1187void DurangoStats::playerSessionResume(int iPad)
1188{
1189 shared_ptr<MultiplayerLocalPlayer> plr = Minecraft::GetInstance()->localplayers[iPad];
1190 if (plr != NULL && plr->level != NULL && plr->level->getLevelData() != NULL)
1191 {
1192 PlayerUID puid;
1193 ProfileManager.GetXUID(iPad, &puid, true);
1194
1195 //EventWritePlayerSessionResume(
1196 app.DebugPrintf(">>>\tPlayerSessionResume(%ls,%s,%ls,%i,%i)\n",
1197 puid.toString().c_str(),
1198 DurangoStats::getPlayerSession(),
1199 DurangoStats::getMultiplayerCorrelationId(),
1200 plr->level->getLevelData()->getGameType()->isSurvival(),
1201 plr->level->difficulty
1202 );
1203
1204 EventWritePlayerSessionResume(
1205 puid.toString().c_str(),
1206 DurangoStats::getPlayerSession(),
1207 DurangoStats::getMultiplayerCorrelationId(),
1208 plr->level->getLevelData()->getGameType()->isSurvival(),
1209 plr->level->difficulty
1210 );
1211 }
1212}
1213
1214void DurangoStats::playerSessionEnd(int iPad)
1215{
1216 shared_ptr<MultiplayerLocalPlayer> plr = Minecraft::GetInstance()->localplayers[iPad];
1217 if (plr != NULL)
1218 {
1219 DurangoStats::getInstance()->travel->flush(plr);
1220 }
1221}