-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.js
148 lines (124 loc) · 5.92 KB
/
index.js
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
'use strict';
const Vec3 = require('vec3');
const Path = require('path');
module.exports = function(bot)
{
// The greatest speedup that can be achieved at this point would be by optimizing the CheckBlockConditions function. It was purposefully built to be dynamic however
// a hardcoded implementation could work so much much faster. That being said the successorconditions.json is not optimized either, one could implement a top
// to bottom search considering the fact that once a block at the top is found, none of the blocks at the bottom will be accessible.
// All in all the user is encouraged to supply his own successor or predecessor functions.
bot.pathfinder = {};
bot.pathfinder.ENUMPathfinder = {ASTAR: 0, DLITE: 1, UDLITE: 2};
bot.pathfinder.ENUMStatus = {Complete: 0, Incomplete: 1, Replan: 2};
Object.defineProperty(bot.pathfinder, 'defaultSuccessors', {
value: require(Path.resolve(__dirname, 'DefaultConditions/successorConditions.json')), enumerable: false,
});
Object.defineProperty(bot.pathfinder, 'defaultPredecessors', {
value: require(Path.resolve(__dirname, 'DefaultConditions/predecessorConditions.json')), enumerable: false,
});
bot.pathfinder.getSuccessors = getCardinalNeighbors.bind(undefined, bot.pathfinder.defaultSuccessors);
bot.pathfinder.getPredecessors = getCardinalNeighbors.bind(undefined, bot.pathfinder.defaultPredecessors);
// Native getBlock implementation too slow for this case
let blocks;
bot.pathfinder.getBlock = function(absolutePoint)
{
if (bot.version) // bot.version may not be yet initialized when run
{
blocks = require('minecraft-data')(bot.version).blocks;
this.getBlock = function(absolutePoint)
{
// Get block cannot correctly identify the ammount of layers of snow at any block
const key = Vec3(euclideanMod(absolutePoint.x, 16), absolutePoint.y, euclideanMod(absolutePoint.z, 16));
const column = bot._chunkColumn(absolutePoint.x - key.x, absolutePoint.z - key.z);
if (!column) return null;
const block = blocks[column.getBlockType(key)];
block.coordinates = absolutePoint;
return block;
};
return this.getBlock(absolutePoint);
}
else
{
console.error(
'ERROR Pathfinder: Bot not yet initialized when getBlock was run,',
'ensure that bot.version is initialized'
);
}
};
// Main function to interact
bot.pathfinder.to = function(Start, End, ENUMPathfinder)
{
if (!ENUMPathfinder || ENUMPathfinder === bot.pathfinder.ENUMPathfinder.ASTAR)
return require(Path.resolve(__dirname, 'Pathfinders/ASTAR.js'))(bot, Start.floored(), End.floored());
else if (ENUMPathfinder === bot.pathfinder.ENUMPathfinder.DLITE)
return require(Path.resolve(__dirname, 'Pathfinders/DLITE.js'))(bot, Start.floored(), End.floored());
};
bot.pathfinder.MAX_EXPANSIONS = 120000; // 100000
bot.pathfinder.HEURISTIC = function(p1, p2) {return p1.distanceTo(p2);};
bot.pathfinder.COST = bot.pathfinder.HEURISTIC;
function getCardinalNeighbors(blockConditions, u)
{
const possiblePositions = [];
for (let m = 0; m < 4; m++)
{
for (let i = 0, il = blockConditions.length; i < il; i++)
checkBlockConditions(possiblePositions, cardinalDirectionVectors3D[m], blockConditions[i], u);
}
return possiblePositions;
}
function checkBlockConditions(possiblePositions, directionVector, blockConditions, playerPosition)
{
let failedCheck = false;
for (let i = 0, il = blockConditions.conditions.length; i < il; i++)
{
// If encountered blockcondition, run recursive function.
// However if encountered noncritical_condition where the root blockcondition already failed the check, skip.
const condition = blockConditions.conditions[i];
const type = condition.type;
if (type === 'blockconditions')
checkBlockConditions(possiblePositions, directionVector, condition, playerPosition);
// Avoids evaulating additional conditions if the check already failed
else if (failedCheck && type === 'nc_condition')
continue;
else
{
const blockWorldCoordinate = Vec3(condition.coordinates).rproduct(directionVector).add(playerPosition);
const blockWorldData = bot.pathfinder.getBlock(blockWorldCoordinate);
if (!blockWorldData || blockWorldData.boundingBox !== condition.condition)
{
failedCheck = true; // If the block did not meet the conditions, the check is failed
if (type === 'condition') break; // However if a condition failed then we can break the loop since no more blocks will meet their conditions.
}
}
}
if (!failedCheck)
possiblePositions.push(Vec3(blockConditions.coordinates).rproduct(directionVector).add(playerPosition));
}
};
const cardinalDirectionVectors3D = [
Vec3(1, 0, -1), // north
Vec3(1, 0, 1), // east
Vec3(-1, 0, 1), // south
Vec3(-1, 0, -1), // west
];
function euclideanMod(numerator, denominator)
{
const result = numerator % denominator;
return result < 0 ? result + denominator : result;
}
Vec3.Vec3.prototype.rproduct = function(vector)
{
// Rotates direction of relative coordinates given in blockConditions
// In some cases the x and z coordinate must be switched, hence the if else statement.
if ( vector.x * vector.z === -1)
{
const _x = this.x;
this.x = this.z*vector.x;
this.z = _x*vector.z;
}
else
{
this.x *= vector.x;
this.z *= vector.z;
} return this;
};