in Minecraft/src/main/java/com/microsoft/Malmo/MissionHandlers/BuildBattleDecoratorImplementation.java [182:275]
private void updateAndScorePlayerVolume(World w, boolean updateReward)
{
int wrongBlocks = 0;
int rightBlocks = 0;
int totalMatchingBlocks = 0;
BlockDrawingHelper drawContext = new BlockDrawingHelper();
drawContext.beginDrawing(w);
for (int x = this.sourceBounds.getMin().getX(); x <= this.sourceBounds.getMax().getX(); x++)
{
for (int y = this.sourceBounds.getMin().getY(); y <= this.sourceBounds.getMax().getY(); y++)
{
for (int z = this.sourceBounds.getMin().getZ(); z <= this.sourceBounds.getMax().getZ(); z++)
{
BlockPos goalStructurePos = new BlockPos(x, y, z);
BlockPos playerStructurePos = goalStructurePos.add(this.delta);
// We don't compare the world's block states, since we re-colour them to give
// feedback on right / wrong blocks.
// Instead, query our internal representations:
IBlockState srcState = getSourceBlockState(w, goalStructurePos);
IBlockState dstState = getDestBlockState(w, playerStructurePos);
if (srcState == null || dstState == null)
continue; // Shouldn't happen unless we've had an out-of-bounds error somehow.
boolean destAir = w.isAirBlock(playerStructurePos);
if (srcState.equals(dstState))
{
// They match. We count this if the dest block is not air.
if (!destAir)
rightBlocks++;
if (blockTypeOnCorrectPlacement != null && !w.isAirBlock(goalStructurePos))
{
// Mark both source and destination blocks for correct placement:
drawContext.setBlockState(w, playerStructurePos, blockTypeOnCorrectPlacement);
drawContext.setBlockState(w, goalStructurePos, blockTypeOnCorrectPlacement);
}
totalMatchingBlocks++;
}
else
{
// Non-match. We call this wrong if the dest block is not air.
if (!destAir)
{
wrongBlocks++;
if (blockTypeOnIncorrectPlacement != null)
{
// Recolour the destination block only:
drawContext.setBlockState(w, playerStructurePos, blockTypeOnIncorrectPlacement);
}
}
// Check the source block - if it was previously correct, and has become incorrect,
// then we will need to reset the world's blockstate:
IBlockState actualState = w.getBlockState(goalStructurePos);
if (!actualState.equals(srcState))
drawContext.setBlockState(w, goalStructurePos, new XMLBlockState(srcState));
}
}
}
}
drawContext.endDrawing(w);
int score = rightBlocks - wrongBlocks;
boolean sendData = false;
boolean sendCompletionBonus = false;
int reward = 0;
if (updateReward && score != this.currentScore)
{
reward = score - this.currentScore;
sendData = true;
}
this.currentScore = score;
if (totalMatchingBlocks == this.structureVolume)
{
if (!this.structureHasBeenCompleted)
{
// The structure has been completed - send the reward bonus.
// We check structureHasBeenCompleted here because we only want to do this once.
// (Otherwise the agent can game the rewards by repeatedly breaking and re-adding the
// final block.)
if (updateReward)
sendCompletionBonus = true;
}
this.structureHasBeenCompleted = true;
}
this.valid = true;
if (sendData)
{
HashMap<String,String> data = new HashMap<String, String>();
data.put("reward", Integer.toString(reward));
data.put("completed", Boolean.toString(sendCompletionBonus));
MalmoMod.safeSendToAll(MalmoMessageType.SERVER_BUILDBATTLEREWARD, data);
}
}