Skip to content

Commit

Permalink
Create a mapping table rather than impromptu matching
Browse files Browse the repository at this point in the history
  • Loading branch information
RussellLVP committed Jun 26, 2020
1 parent b6e3918 commit 3a9783c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
49 changes: 33 additions & 16 deletions javascript/features/collectables/treasures.js
Expand Up @@ -33,12 +33,11 @@ export class Treasures extends CollectableBase {

// Map from Player instance => Map of Pickup instance to collectable Id
playerPickups_ = new Map();
playerSeeds_ = new Map();
playerTreasureMapping_ = new Map();

// Set of all collectable IDs, so quickly be able to initialize and diff
books_ = new Set();
treasures_ = new Set();
treasuresArray_ = [];

constructor(collectables, manager) {
super({
Expand Down Expand Up @@ -77,7 +76,6 @@ export class Treasures extends CollectableBase {
});

this.treasures_.add(info.id);
this.treasuresArray_.push(info.id);
}
}

Expand All @@ -93,7 +91,7 @@ export class Treasures extends CollectableBase {
pickup.dispose();

this.playerPickups_.delete(player);
this.playerSeeds_.delete(player);
this.playerTreasureMapping_.delete(player);

// Prune the scoped entities to get rid of references to deleted objects.
this.entities.prune();
Expand All @@ -106,6 +104,7 @@ export class Treasures extends CollectableBase {
if (this.playerPickups_.has(player))
this.clearCollectablesForPlayer(player);

this.createTreasureMapping(player);
this.setPlayerStatistics(player, statistics);

const pickups = new Map();
Expand Down Expand Up @@ -150,21 +149,39 @@ export class Treasures extends CollectableBase {

// ---------------------------------------------------------------------------------------------

// Computes the collectableId representing the treasure that will be unlocked when the given
// |bookCollectableId| has been unlocked for the given |player|.
determineTreasureForBookForPlayer(player, bookCollectableId) {
if (!this.playerSeeds_.has(player)) {
this.playerSeeds_.set(player,
player.account.isIdentified() ? player.account.userId
: murmur3hash(player.name));
// Creates the book Id => treasure Id mapping for the given |player|. This is different for
// each player, because we're mean and want to stop collaboration :)
createTreasureMapping(player) {
const treasureCount = this.treasures_.size;
const treasures = [ ...this.treasures_ ];

const uniqueValue = player.account.isIdentified() ? player.account.userId
: player.name;

const seed = createSeed(`TR:${uniqueValue}`);
const mapping = new Map();

for (const collectableId of this.books_) {
const index = randomSeed(seed, treasures.length);
const treasureId = treasures.splice(index, 1)[0];

mapping.set(collectableId, treasureId);
}

const seed = this.playerSeeds_.get(player) + bookCollectableId;
this.playerTreasureMapping_.set(player, mapping);
}

const treasureCount = this.treasures_.size;
const treasureIndex = randomSeed(createSeed(seed.toString(24)), treasureCount);
// Computes the collectableId representing the treasure that will be unlocked when the given
// |bookCollectableId| has been unlocked for the given |player|.
determineTreasureForBookForPlayer(player, bookCollectableId) {
if (!this.playerTreasureMapping_.has(player))
throw new Error(`Treasure mappings have not been initialized for the given ${player}`);

const mapping = this.playerTreasureMapping_.get(player);
if (!mapping.has(bookCollectableId))
throw new Error(`The given book collectable Id (${bookCollectableId}) is not mapped.`);

return this.treasuresArray_[treasureIndex];
return mapping.get(bookCollectableId);
}

// ---------------------------------------------------------------------------------------------
Expand All @@ -173,6 +190,6 @@ export class Treasures extends CollectableBase {
super.dispose(); // will delete all entities

this.playerPickups_.clear();
this.playerSeeds_.clear();
this.playerTreasureMapping_.clear();
}
}
9 changes: 8 additions & 1 deletion javascript/features/collectables/treasures.test.js
Expand Up @@ -81,6 +81,9 @@ describe('Treasures', (it, beforeEach) => {
it('should be able to determine the treasure Id for a given book Id', async (assert) => {
const russell = server.playerManager.getById(/* Russell= */ 1);

delegate.createTreasureMapping(gunther);
delegate.createTreasureMapping(russell);

// (1) Results for the same player are identical, but are different for different players.
assert.equal(
delegate.determineTreasureForBookForPlayer(gunther, 10),
Expand All @@ -103,6 +106,8 @@ describe('Treasures', (it, beforeEach) => {

await gunther.identify({ userId: 12345 });

delegate.createTreasureMapping(gunther);

const userTreasure = delegate.determineTreasureForBookForPlayer(gunther, 30);
assert.notEqual(nameTreasure, userTreasure);

Expand All @@ -112,7 +117,9 @@ describe('Treasures', (it, beforeEach) => {
delegate.determineTreasureForBookForPlayer(russell, 35));

await russell.identify({ userId: 12345 });


delegate.createTreasureMapping(russell);

assert.equal(
delegate.determineTreasureForBookForPlayer(gunther, 35),
delegate.determineTreasureForBookForPlayer(russell, 35));
Expand Down

0 comments on commit 3a9783c

Please sign in to comment.