-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.js
143 lines (124 loc) · 5.81 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
EventEmitter = require('events').EventEmitter;
const Vec3 = require('vec3');
const Path = require('path');
const optVer = require('minecraft-protocol/src/version').defaultVersion;
const blockData = require('minecraft-data')(optVer).blocks;
module.exports = function(bot)
{
// The greatest speedup that can be achieved at this point would be by optimizing the cBC 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.
bot.navigate = new EventEmitter();
bot.navigate.ENUMPathfinder = {ASTAR: 0, DLITE: 1, UDLITE: 2};
bot.navigate.ENUMStatus = {Complete: 0, Incomplete: 1};
bot.navigate.getSuccessors = gMS.bind(undefined, require(Path.resolve(__dirname, 'DefaultConditions/successorConditions.json')));
bot.navigate.getPredecessors = gMS.bind(undefined, require(Path.resolve(__dirname, 'DefaultConditions/successorConditions.json')));
// Native getBlock implementation too slow for this case
bot.navigate.getBlock = function(absolutePoint)
{
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; else return blockData[column.getBlockType(key)];
};
// Main function to interact
bot.navigate.to = function(Start, End, ENUMPathfinder)
{
if (!ENUMPathfinder || ENUMPathfinder === bot.navigate.ENUMPathfinder.ASTAR)
return require(Path.resolve(__dirname, 'Pathfinders/ASTAR.js'))(bot, Start.floored(), End.floored());
else if (ENUMPathfinder === bot.navigate.ENUMPathfinder.DLITE)
return require(Path.resolve(__dirname, 'Pathfinders/DLITE.js'))(bot, Start.floored(), End.floored());
else if (ENUMPathfinder === bot.navigate.ENUMPathfinder.UDLITE)
return require(Path.resolve(__dirname, 'Pathfinders/UDLITE.js'))(bot, Start.floored(), End.floored());
};
// bot.navigate.SCAFFOLD = false;
bot.navigate.MAX_EXPANSIONS = 10000; // 100000
bot.navigate.HEURISTIC = function(s1, s2) {return s1.p.distanceTo(s2.p);};
bot.navigate.COST = function(s1, s2) {return s1.p.distanceTo(s2.p);};
// Block condition functions
function gMS(blockConditions, u)
{
const possiblePositions = [];
for (let m = 0; m < 4; m++)
{
for (let i = 0, il = blockConditions.length; i < il; i++)
{
const pos = cBC(cardinalDirectionVectors3D[m], blockConditions[i], u);
if (pos) {possiblePositions.push(pos); break;}
}
}
return possiblePositions;
}
function cBC(m, 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];
if (condition)
{
const type = condition.type;
if (type === 'blockconditions')
{
// Terminates early if a possible position is already found.
if (!failedCheck) return Vec3(blockConditions.coordinates).rproduct(m).add(playerPosition);
return cBC(m, condition, playerPosition);
}
else if (type === 'nc_condition' && failedCheck)
{
// Avoids evaulating additional conditions if the check already failed
continue;
}
else
{
const blockWorldCoordinate = Vec3(condition.coordinates).rproduct(m).add(playerPosition);
const blockWorldData = bot.navigate.getBlock(blockWorldCoordinate);
if (
blockWorldData &&
(
(condition.condition === 'empty' && blockWorldData.boundingBox !== 'empty') ||
(condition.condition === 'solid' && blockWorldData.boundingBox !== 'block')
)
)
{
if (type === 'condition') break; // If the block did not meet the conditions, the check is failed
failedCheck = true; // However if a condition failed then we can break the loop since no more blocks will meet their conditions.
}
}
}
else
{
if (!failedCheck) return Vec3(blockConditions.coordinates).rproduct(m).add(playerPosition);
return undefined;
}
}
}
};
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;
};