-
-
Save YetiBots/6c933f34f22e62ecd18eec7a88011388 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Constants // | |
//----------------------------------------------------------------------------// | |
const GameInstance = require ("./game_instance"); | |
//----------------------------------------------------------------------------// | |
// Export // | |
//----------------------------------------------------------------------------// | |
module.exports = class | |
{ | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Creates a new application controller | |
constructor (updateRate, updateFunc) | |
{ | |
this._updateRate = updateRate; | |
this._updateFunc = updateFunc; | |
this._gameInstance = new GameInstance(); | |
console.log ("Select a WoW Window..."); | |
this._heartbeat(); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Main event loop executed by the heartbeat | |
_eventLoop() | |
{ | |
// Waits for a game to get selected | |
if (!this._gameInstance.isSelected()) | |
{ | |
this._gameInstance.selectByActiveWindow(); | |
return; | |
} | |
// Ensures the game is still running | |
if (!this._gameInstance.isRunning()) | |
{ | |
console.log ("Select a WoW Window..."); | |
this._gameInstance.deselect(); return; | |
} | |
// Checks whether the player is in-game | |
if (!this._gameInstance.memory.readBool | |
(this._gameInstance.offsets.GameState + | |
this._gameInstance.module)) return; | |
// Call the specified update function | |
this._updateFunc (this._gameInstance); | |
// Don't forget to reset memory cache | |
this._gameInstance.memory.clearCache(); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Performs heartbeat and enqueues the next one | |
_heartbeat() | |
{ | |
this._eventLoop(); | |
setTimeout (() => | |
this._heartbeat(), | |
this._updateRate); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Aura Monitor // | |
//----------------------------------------------------------------------------// | |
// Used to retrieve player guid | |
let guidBuff = new Buffer (16); | |
// We need timer to calculate aura times | |
const Timer = require ("robot-js").Timer; | |
// Create application controller | |
new (require ("./app_controller")) | |
(250, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
const auraOff = offsets.Entity.Unit.Aura; | |
const player = memory.readPtr | |
// Retrieve the player pointer | |
(module + offsets.LocalPlayer); | |
// Validate the pointer | |
if (player <= 0) return; | |
// When less than 16 Auras, they are stored in an array | |
let count = memory.readInt32 (player + auraOff.Count1); | |
let table = player + auraOff.TableBase1; | |
// Using the heap | |
if (count === -1) | |
{ | |
// The auras were dynamically allocated on the heap | |
count = memory.readInt32 (player + auraOff.Count2); | |
table = memory.readPtr (player + auraOff.TableBase2); | |
} | |
// Make sure count and table are valid | |
if (count <= 0 || table <= 0) return; | |
let auras = [ ]; | |
// Loop through all aura entries | |
for (let i = 0; i < count; ++i) | |
{ | |
// Get the current aura entry offset in memory | |
const slide = table + (auraOff.EntrySize * i); | |
// Skip the current entry if the aura spell ID is zero | |
if (!memory.readInt32 (slide + auraOff.Entry.SpellID)) | |
continue; | |
auras.push | |
({ | |
owner : memory.readData (slide + auraOff.Entry.Owner, guidBuff, 16) ? | |
guidBuff.toString ("hex").toUpperCase() : "", | |
spellID: memory.readInt32 (slide + auraOff.Entry.SpellID), | |
flags : memory.readInt8 (slide + auraOff.Entry.Flags ), | |
stacks : memory.readInt8 (slide + auraOff.Entry.Stacks ), | |
level : memory.readInt8 (slide + auraOff.Entry.Level ), | |
endTime: memory.readInt32 (slide + auraOff.Entry.EndTime) | |
}); | |
} | |
// Cheap way to clear the screen | |
process.stdout.write ("\x1Bc"); | |
// Retrieve the current Cpu Time | |
const now = Timer.getCpuTime(); | |
// Print each aura | |
auras.map (aura => | |
{ | |
// TIP: SpellID is a spell so you can use the WowAPI | |
// or WowHead to retrieve more information about it | |
// Convert WoW's time using the current time | |
const timeLeft = (aura.endTime - now) / 1000; | |
console.log (`Spell=${aura.spellID} Flags=${aura.flags} Stack=${ | |
aura.stacks} TimeLeft=${timeLeft > 0 ? timeLeft : 0}s`); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// BMAH Monitor // | |
//----------------------------------------------------------------------------// | |
// Create application controller | |
new (require ("./app_controller")) | |
(250, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
// Read BMAH count and table | |
const count = memory.readInt32 (module + offsets.BMAH.Count ); | |
const table = memory.readPtr (module + offsets.BMAH.TableBase); | |
// Make sure count and table are valid | |
if (count <= 0 || table <= 0) return; | |
let items = [ ]; | |
// Loop through all BMAH items | |
for (let i = 0; i < count; ++i) | |
{ | |
// Retrieve the current BMAH item offset in memory | |
const slide = table + (offsets.BMAH.EntrySize * i); | |
items.push | |
({ | |
marketID : memory.readInt32 (slide + offsets.BMAH.Entry.MarketID ), | |
itemID : memory.readInt32 (slide + offsets.BMAH.Entry. ItemID ), | |
minimumBid: memory.readInt64 (slide + offsets.BMAH.Entry.MinimumBid), | |
maximumInc: memory.readInt64 (slide + offsets.BMAH.Entry.MaximumInc), | |
currentBid: memory.readInt64 (slide + offsets.BMAH.Entry.CurrentBid), | |
timeLeft : memory.readInt32 (slide + offsets.BMAH.Entry.TimeLeft ), | |
bidCount : memory.readInt32 (slide + offsets.BMAH.Entry.BidCount ) | |
}); | |
} | |
// Cheap way to clear the screen | |
process.stdout.write ("\x1Bc"); | |
// Print each item | |
items.map (item => | |
{ | |
// TIP: ItemID is an item so you can use the WowAPI | |
// or WowHead to retrieve more information about it | |
console.log (`Item=${item.itemID} Bid=${item.currentBid / | |
10000} Bids=${item.bidCount} Time=${item.timeLeft}`); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Chat Monitor // | |
//----------------------------------------------------------------------------// | |
// Old chat position | |
let position = null; | |
// Used to retrieve player guid | |
let guidBuff = new Buffer (16); | |
// Create application controller | |
new (require ("./app_controller")) | |
(250, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
// Read the new position of the chat | |
const newPosition = memory.readInt32 | |
(module + offsets.Chat.Position); | |
// Make sure the position is reasonable | |
if (newPosition < 0 || newPosition > 60) | |
return; | |
if (position === null) | |
{ | |
// First time this is being run | |
position = newPosition; return; | |
} | |
let newMessages = [ ]; | |
// Read any new incoming messages | |
while (position !== newPosition) | |
{ | |
if (++position === 60) position = 0; | |
// Get the current message offset in memory | |
const slide = module + offsets.Chat.TableBase + | |
(offsets.Chat.EntrySize * (position - 1)); | |
newMessages.push | |
({ | |
senderGuid : memory.readData (slide + offsets.Chat.Entry.SenderGuid, guidBuff, 16) ? | |
guidBuff.toString ("hex").toUpperCase() : "", | |
senderName : memory.readString (slide + offsets.Chat.Entry.SenderName, 40 ), | |
fullMessage: memory.readString (slide + offsets.Chat.Entry.FullMessage, 3000), | |
onlyMessage: memory.readString (slide + offsets.Chat.Entry.OnlyMessage, 3000), | |
channelNum : memory.readInt32 (slide + offsets.Chat.Entry.ChannelNum), | |
timeStamp : memory.readInt32 (slide + offsets.Chat.Entry.TimeStamp ) | |
}); | |
} | |
// Process each new message | |
newMessages.map (message => | |
{ | |
// Convert the Unix timestamp into a normal Date | |
const date = new Date (message.timeStamp * 1000); | |
const hrs = `0${date.getHours ()}`.substr (-2); | |
const min = `0${date.getMinutes()}`.substr (-2); | |
const sec = `0${date.getSeconds()}`.substr (-2); | |
console.log (`[${hrs}:${min}:${sec}] [${message.senderName}]: ${message.onlyMessage}`); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Cooldown Monitor // | |
//----------------------------------------------------------------------------// | |
// We need timer to calculate aura times | |
const Timer = require ("robot-js").Timer; | |
// Create application controller | |
new (require ("./app_controller")) | |
(250, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
let entry = memory.readPtr | |
// Retrieve the first cooldown entry | |
(module + offsets.Cooldown.TableBase); | |
let cooldowns = [ ]; | |
let repeater = { }; | |
let infinite = 0; | |
// Read all entries from first to last | |
while (entry > 0 && (entry & 1) === 0) | |
{ | |
// Avoid repetition of entries | |
if (repeater[entry]) break; | |
else repeater[entry] = true; | |
// Avoid possible infinite loop | |
if (++infinite >= 20000) break; | |
cooldowns.push | |
({ | |
spellID : memory.readInt32 (entry + offsets.Cooldown.Entry.SpellID ), | |
itemID : memory.readInt32 (entry + offsets.Cooldown.Entry. ItemID ), | |
spellStartTime: memory.readInt32 (entry + offsets.Cooldown.Entry.SpellStartTime), | |
spellDuration : memory.readInt32 (entry + offsets.Cooldown.Entry.SpellDuration ), | |
groupID : memory.readInt32 (entry + offsets.Cooldown.Entry.GroupID ), | |
groupStartTime: memory.readInt32 (entry + offsets.Cooldown.Entry.GroupStartTime), | |
groupDuration : memory.readInt32 (entry + offsets.Cooldown.Entry.GroupDuration ), | |
isActive : memory.readBool (entry + offsets.Cooldown.Entry.IsActive ), | |
gcdStartTime : memory.readInt32 (entry + offsets.Cooldown.Entry.GcdStartTime ), | |
gcdDuration : memory.readInt32 (entry + offsets.Cooldown.Entry.GcdDuration ) | |
}); | |
// Read the next entry in table | |
entry = memory.readPtr (entry + | |
offsets.Cooldown.EntryNext); | |
} | |
// Cheap way to clear the screen | |
process.stdout.write ("\x1Bc"); | |
// Retrieve the current Cpu Time | |
const now = Timer.getCpuTime(); | |
// Print each cooldown | |
cooldowns.map (cd => | |
{ | |
// TIP: More information about SpellID and ItemID | |
// can be retrieved through the WowAPI or WowHead | |
const endGCD = cd.gcdStartTime + cd.gcdDuration; | |
const endTime = (cd.spellStartTime || cd.groupStartTime) + | |
(cd.spellDuration || cd.groupDuration ); | |
const remGCD = endGCD - now; | |
const remTime = endTime - now; | |
console.log (`Spell=${cd.spellID} Item=${cd.itemID} RemGCD=${remGCD > 0 ? remGCD / | |
1000 : 0}s RemTime=${remTime > 0 ? remTime / 1000 : 0}s IsActive=${cd.isActive}`); | |
// WARNING: This algorithm is not completely accurate and | |
// may return incorrect results during certain conditions | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Entity Dumper // | |
//----------------------------------------------------------------------------// | |
// Create application controller | |
new (require ("./app_controller")) | |
(250, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
let entry = memory.readPtr | |
// Retrieve the entity list manager | |
(module + offsets.Entity.TableBase); | |
// Validate the pointer | |
if (entry <= 0) return; | |
entry = memory.readPtr | |
// Retrieve the first entity entry | |
(entry + offsets.Entity.EntryFirst); | |
let entities = { | |
npcs : [ ], | |
players: [ ], | |
objects: [ ] | |
}; | |
let repeater = { }; | |
let infinite = 0; | |
// Read all entries from first to last | |
while (entry > 0 && (entry & 1) === 0) | |
{ | |
// Avoid repetition of entries | |
if (repeater[entry]) break; | |
else repeater[entry] = true; | |
// Avoid possible infinite loop | |
if (++infinite >= 20000) break; | |
// Retrieve type and descriptor | |
const type = memory.readInt32 (entry + offsets.Entity.Entry.Type ); | |
const desc = memory.readPtr (entry + offsets.Entity.Entry.Descriptors); | |
if (desc > 0) | |
{ | |
type === 3 && entities.npcs.push | |
({ | |
entry, | |
x: memory.readReal32 (entry + offsets.Entity.Unit.Origin + 0), | |
y: memory.readReal32 (entry + offsets.Entity.Unit.Origin + 4), | |
z: memory.readReal32 (entry + offsets.Entity.Unit.Origin + 8) | |
}); | |
type === 4 && entities.players.push | |
({ | |
entry, | |
x: memory.readReal32 (entry + offsets.Entity.Unit.Origin + 0), | |
y: memory.readReal32 (entry + offsets.Entity.Unit.Origin + 4), | |
z: memory.readReal32 (entry + offsets.Entity.Unit.Origin + 8) | |
}); | |
type === 5 && entities.objects.push | |
({ | |
entry, | |
x: memory.readReal32 (entry + offsets.Entity.Object.Origin + 0), | |
y: memory.readReal32 (entry + offsets.Entity.Object.Origin + 4), | |
z: memory.readReal32 (entry + offsets.Entity.Object.Origin + 8) | |
}); | |
} | |
// Read the next entry in table | |
entry = memory.readPtr (entry + | |
offsets.Entity.EntryNext); | |
} | |
for (let e in entities) | |
{ | |
console.log (`\n${e}`); | |
// Print grouped entities | |
entities[e].map (entity => | |
{ | |
console.log (`entry=${entity.entry.toString (16).toUpperCase()} x=${entity.x.toFixed (2)} y=${entity.y.toFixed (2)} z=${entity.z.toFixed (2)}`); | |
}); | |
} | |
// All finished | |
process.exit(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Fishing Bot // | |
//----------------------------------------------------------------------------// | |
// Used to retrieve player guid | |
let guidBuff = new Buffer (16); | |
// We need a keyboard to cast the fishing pole | |
const Keyboard = require ("robot-js").Keyboard(); | |
// Create application controller | |
new (require ("./app_controller")) | |
(500, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
const player = memory.readPtr | |
// Retrieve the player pointer | |
(module + offsets.LocalPlayer); | |
let entry = memory.readPtr | |
// Retrieve the entity list manager | |
(module + offsets.Entity.TableBase); | |
// Make sure player and entry are valid | |
if (player <= 0 || entry <= 0) return; | |
entry = memory.readPtr | |
// Retrieve the first entity entry | |
(entry + offsets.Entity.EntryFirst); | |
let lPlayer = { }; | |
let bobbers = [ ]; | |
let repeater = { }; | |
let infinite = 0; | |
// Read all entries from first to last | |
while (entry > 0 && (entry & 1) === 0) | |
{ | |
// Avoid repetition of entries | |
if (repeater[entry]) break; | |
else repeater[entry] = true; | |
// Avoid possible infinite loop | |
if (++infinite >= 20000) break; | |
// Retrieve type and descriptor | |
const type = memory.readInt32 (entry + offsets.Entity.Entry.Type ); | |
const desc = memory.readPtr (entry + offsets.Entity.Entry.Descriptors); | |
if (desc > 0) | |
{ | |
// Check local player | |
if (entry === player) | |
{ | |
const guid = memory.readData (desc + offsets.Entity.Entry.Desc.GlobalID, | |
guidBuff, 16) ? guidBuff.toString ("hex").toUpperCase():""; | |
const isLooting = memory.readBool (module + offsets.IsLooting ); | |
const isChannel = memory.readInt32 (entry + offsets.Entity.Unit.Channel); | |
lPlayer = { guid, isLooting, isChannel }; | |
} | |
// Maybe bobber | |
if (type === 5) | |
{ | |
const guid = memory.readData (desc + offsets.Entity.Entry.Desc.GlobalID, | |
guidBuff, 16) ? guidBuff.toString ("hex").toUpperCase():""; | |
const bobbing = memory.readBool (entry + offsets.Entity.Object.Bobbing); | |
const creator = memory.readData (desc + offsets.Entity.Object.Desc.Creator, | |
guidBuff, 16) ? guidBuff.toString ("hex").toUpperCase():""; | |
const display = memory.readInt32 (desc + offsets.Entity.Object.Desc.Display); | |
if (guid && display === 668) bobbers.push ({ guid, bobbing, creator }); | |
} | |
} | |
// Read the next entry in table | |
entry = memory.readPtr (entry + | |
offsets.Entity.EntryNext); | |
} | |
// Player is still looting fish | |
if (lPlayer.isLooting) return; | |
// Cast the fishing pole | |
if (!lPlayer.isChannel) | |
Keyboard.click ("0"); | |
// Check the bobbers | |
bobbers.map (bobber => | |
{ | |
// Check if bobber belongs to the player and is bobbing | |
if (bobber.creator === lPlayer.guid && bobber.bobbing) | |
{ | |
// Pretend to mouse over the bobber | |
guidBuff.fill (bobber.guid, "hex"); | |
memory.writeData (module + offsets | |
.MouseGuid, guidBuff, 16); | |
// Interact with it | |
Keyboard.click ("`"); | |
} | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Constants // | |
//----------------------------------------------------------------------------// | |
const Robot = require ("robot-js" ); | |
const Offsets = require ("./offsets"); | |
// Shortcuts to Robot classes | |
const Process = Robot.Process; | |
const Module = Robot.Module; | |
const Memory = Robot.Memory; | |
const Window = Robot.Window; | |
//----------------------------------------------------------------------------// | |
// Export // | |
//----------------------------------------------------------------------------// | |
module.exports = class | |
{ | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Creates a new unselected game instance object | |
constructor() { this.deselect(); } | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Deselects any currently selected game instance | |
deselect() | |
{ | |
this._window = null; // The game window | |
this._process = null; // The game process | |
this._is64Bit = false; // If game is 64Bit | |
this._memory = null; // The game memory | |
this._module = null; // Main module addr | |
this._offsets = null; // Correct offsets | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Selects a game instance using the specified process | |
selectByProcess (process) | |
{ | |
// Check if arguments are correct | |
if (!(process instanceof Process)) | |
throw new TypeError ("Invalid arguments"); | |
// Attempt to select the main window | |
let window = process.getWindows()[0]; | |
return window && | |
// Perform window selection | |
this.selectByWindow (window); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Selects a game instance using the specified window | |
selectByWindow (window) | |
{ | |
// Check if arguments are correct | |
if (!(window instanceof Window)) | |
throw new TypeError ("Invalid arguments"); | |
// Check if the window title correctly matches | |
if (window.getTitle() !== "World of Warcraft") | |
return false; | |
let process = window.getProcess(); | |
// Ensure that the process was opened | |
if (!process.isValid()) return false; | |
let module = | |
// Get the main executable module | |
process.getModules (".*\.exe")[0]; | |
if (!module) return false; | |
module = module.getBase(); | |
// Determine if game is 64Bit | |
let is64Bit = process.is64Bit(); | |
let offsets = is64Bit ? | |
// Make sure to select correct offsets | |
Offsets.Offsets64 : Offsets.Offsets32; | |
// Create a new memory object | |
let memory = Memory (process); | |
if (memory.readString | |
// Ensure game build is supported | |
(module + offsets.GameBuild, 6) !== | |
Offsets.GameBuild) return false; | |
this._window = window; | |
this._process = process; | |
this._is64Bit = is64Bit; | |
this._memory = memory; | |
this._module = module; | |
this._offsets = offsets; | |
// Create the memory cache | |
this._memory.createCache | |
(16384, 4096, 10485760); | |
return true; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Selects a game instance by scanning all open processes | |
selectByFindProcess() | |
{ | |
for (let p of Process.getList ("Wow.*\.exe")) | |
{ | |
// Select the first suitable process value | |
if (this.selectByProcess (p)) return true; | |
} | |
return false; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Selects a game instance by scanning all open windows | |
selectByFindWindow() | |
{ | |
for (let w of Window.getList ("World of Warcraft")) | |
{ | |
// Select the first suitable window value | |
if (this.selectByWindow (w)) return true; | |
} | |
return false; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Selects a game instance using the current active window | |
selectByActiveWindow() | |
{ | |
// Attempt to select the current active window | |
return this.selectByWindow (Window.getActive()); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Returns true if a game instance is currently selected | |
isSelected() | |
{ | |
return this._window !== null; | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Returns true if the selected game instance is running | |
isRunning() | |
{ | |
// Ensure a game window is selected | |
if (!this.isSelected()) return false; | |
return !this._process.hasExited() && | |
this._window .isValid (); | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Various properties to extract game instance information | |
get window () { return this._window; } | |
get process() { return this._process; } | |
get is64Bit() { return this._is64Bit; } | |
get memory () { return this._memory; } | |
get module () { return this._module; } | |
get offsets() { return this._offsets; } | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Offsets // | |
//----------------------------------------------------------------------------// | |
module.exports = | |
{ | |
GameBuild : "21463", | |
Offsets32: | |
{ | |
GameHash : 0xC7FEDA45, | |
IconHash : 0xA118EC28, | |
GameBuild : 0x9B24E4, | |
GameState : 0xDA55B2, | |
LocalPlayer : 0xD2E4C0, | |
LocalCont : 0xBB3F7C, | |
LocalZone : 0xBC0A64, | |
IsLooting : 0xE165C8, | |
IsTexting : 0xC1EB08, | |
MouseGuid : 0xDA5988, | |
TargetGuid : 0xDA59B8, | |
Camera: | |
{ | |
Struct : 0xDA5D58, | |
Offset : 0x7610, | |
Origin : 0x08, | |
Matrix : 0x14, | |
Fov : 0x38 | |
}, | |
Entity: | |
{ | |
TableBase : 0xC9D530, | |
EntryFirst : 0x0C, | |
EntryNext : 0x3C, | |
Entry: | |
{ | |
Type : 0x0C, | |
Descriptors : 0x04, | |
Desc: | |
{ | |
GlobalID : 0x00, | |
EntityID : 0x24, | |
DynFlags : 0x28 | |
} | |
}, | |
Unit: | |
{ | |
Transport : 0xAB0, | |
Origin : 0xAC0, | |
Angle : 0xAD0, | |
Casting : 0xF98, | |
CastingStarted : 0xFB0, | |
CastingWillEnd : 0xFB4, | |
Channel : 0xFB8, | |
ChannelStarted : 0xFBC, | |
ChannelWillEnd : 0xFC0, | |
Aura: | |
{ | |
Count1 : 0x1588, | |
Count2 : 0x1108, | |
TableBase1 : 0x1108, | |
TableBase2 : 0x110C, | |
EntrySize : 0x48, | |
Entry: | |
{ | |
Owner : 0x20, | |
SpellID : 0x30, | |
Flags : 0x38, | |
Stacks : 0x39, | |
Level : 0x3A, | |
EndTime : 0x40 | |
} | |
}, | |
Desc: | |
{ | |
Creator : 0x080, | |
Health : 0x0F0, | |
Power : 0x0F4, | |
HealthMax : 0x10C, | |
PowerMax : 0x110, | |
Level : 0x158, | |
Flags : 0x17C | |
} | |
}, | |
NPC: | |
{ | |
Name1 : 0xC38, | |
Name2 : 0x07C | |
}, | |
Player: | |
{ | |
Money1 : 0x190C, | |
Money2 : 0x1890, | |
Arch : 0x1910, | |
ArchCount : 0x08, | |
ArchSites : 0x10, | |
Target : 0x41E8 | |
}, | |
Object: | |
{ | |
Bobbing : 0x104, | |
Transport : 0x130, | |
Origin : 0x140, | |
Rotation : 0x150, | |
Transform : 0x278, | |
Name1 : 0x274, | |
Name2 : 0x0B4, | |
Desc: | |
{ | |
Creator : 0x030, | |
Display : 0x040 | |
} | |
} | |
}, | |
NameCache: | |
{ | |
TableBase : 0xC6043C, | |
EntryNext : 0x00, | |
Entry: | |
{ | |
Guid : 0x10, | |
Name : 0x21, | |
Race : 0x70, | |
Class : 0x78 | |
} | |
}, | |
Cooldown: | |
{ | |
TableBase : 0xC8AC88, | |
EntryNext : 0x04, | |
Entry: | |
{ | |
SpellID : 0x08, | |
ItemID : 0x0C, | |
SpellStartTime : 0x10, | |
SpellDuration : 0x14, | |
GroupID : 0x18, | |
GroupStartTime : 0x1C, | |
GroupDuration : 0x20, | |
IsActive : 0x24, | |
GcdStartTime : 0x28, | |
GcdDuration : 0x30 | |
} | |
}, | |
BMAH: | |
{ | |
Count : 0xE536D0, | |
TableBase : 0xE536D4, | |
EntrySize : 0x70, | |
Entry: | |
{ | |
MarketID : 0x00, | |
ItemID : 0x08, | |
MinimumBid : 0x48, | |
MaximumInc : 0x50, | |
CurrentBid : 0x58, | |
TimeLeft : 0x60, | |
BidCount : 0x68 | |
} | |
}, | |
Chat: | |
{ | |
Position : 0xE01894, | |
TableBase : 0xDA7518, | |
EntrySize : 0x17E8, | |
Entry: | |
{ | |
SenderGuid : 0x0000, | |
SenderName : 0x0034, | |
FullMessage : 0x0065, | |
OnlyMessage : 0x0C1D, | |
ChannelNum : 0x17D8, | |
TimeStamp : 0x17E4 | |
} | |
} | |
}, | |
Offsets64: | |
{ | |
GameHash : 0x64C90819, | |
IconHash : 0xA118EC28, | |
GameBuild : 0x0F415FC, | |
GameState : 0x1519A7E, | |
LocalPlayer : 0x147E680, | |
LocalCont : 0x124B40C, | |
LocalZone : 0x125F694, | |
IsLooting : 0x158D1A4, | |
IsTexting : 0x12CD4B0, | |
MouseGuid : 0x151A0B8, | |
TargetGuid : 0x151A0E8, | |
Camera: | |
{ | |
Struct : 0x151A520, | |
Offset : 0x7768, | |
Origin : 0x10, | |
Matrix : 0x1C, | |
Fov : 0x40 | |
}, | |
Entity: | |
{ | |
TableBase : 0x135D120, | |
EntryFirst : 0x18, | |
EntryNext : 0x68, | |
Entry: | |
{ | |
Type : 0x18, | |
Descriptors : 0x08, | |
Desc: | |
{ | |
GlobalID : 0x00, | |
EntityID : 0x24, | |
DynFlags : 0x28 | |
} | |
}, | |
Unit: | |
{ | |
Transport : 0x1538, | |
Origin : 0x1548, | |
Angle : 0x1558, | |
Casting : 0x1B98, | |
CastingStarted : 0x1BB0, | |
CastingWillEnd : 0x1BB4, | |
Channel : 0x1BB8, | |
ChannelStarted : 0x1BBC, | |
ChannelWillEnd : 0x1BC0, | |
Aura: | |
{ | |
Count1 : 0x2390, | |
Count2 : 0x1D10, | |
TableBase1 : 0x1D10, | |
TableBase2 : 0x1D18, | |
EntrySize : 0x68, | |
Entry: | |
{ | |
Owner : 0x40, | |
SpellID : 0x50, | |
Flags : 0x58, | |
Stacks : 0x59, | |
Level : 0x5A, | |
EndTime : 0x60 | |
} | |
}, | |
Desc: | |
{ | |
Creator : 0x080, | |
Health : 0x0F0, | |
Power : 0x0F4, | |
HealthMax : 0x10C, | |
PowerMax : 0x110, | |
Level : 0x158, | |
Flags : 0x17C | |
} | |
}, | |
NPC: | |
{ | |
Name1 : 0x16F0, | |
Name2 : 0x00A0 | |
}, | |
Player: | |
{ | |
Money1 : 0x2790, | |
Money2 : 0x1890, | |
Arch : 0x2798, | |
ArchCount : 0x08, | |
ArchSites : 0x18, | |
Target : 0x77E8, | |
}, | |
Object: | |
{ | |
Bobbing : 0x1E0, | |
Transport : 0x238, | |
Origin : 0x248, | |
Rotation : 0x258, | |
Transform : 0x4A0, | |
Name1 : 0x498, | |
Name2 : 0x0D8, | |
Desc: | |
{ | |
Creator : 0x030, | |
Display : 0x040 | |
} | |
} | |
}, | |
NameCache: | |
{ | |
TableBase : 0x1316E98, | |
EntryNext : 0x00, | |
Entry: | |
{ | |
Guid : 0x20, | |
Name : 0x31, | |
Race : 0x88, | |
Class : 0x90 | |
} | |
}, | |
Cooldown: | |
{ | |
TableBase : 0x1354D50, | |
EntryNext : 0x08, | |
Entry: | |
{ | |
SpellID : 0x10, | |
ItemID : 0x14, | |
SpellStartTime : 0x18, | |
SpellDuration : 0x1C, | |
GroupID : 0x20, | |
GroupStartTime : 0x24, | |
GroupDuration : 0x28, | |
IsActive : 0x2C, | |
GcdStartTime : 0x30, | |
GcdDuration : 0x38 | |
} | |
}, | |
BMAH: | |
{ | |
Count : 0x15CE6E8, | |
TableBase : 0x15CE6F0, | |
EntrySize : 0xA8, | |
Entry: | |
{ | |
MarketID : 0x00, | |
ItemID : 0x08, | |
MinimumBid : 0x80, | |
MaximumInc : 0x88, | |
CurrentBid : 0x90, | |
TimeLeft : 0x98, | |
BidCount : 0xA0 | |
} | |
}, | |
Chat: | |
{ | |
Position : 0x157627C, | |
TableBase : 0x151BD20, | |
EntrySize : 0x17F0, | |
Entry: | |
{ | |
SenderGuid : 0x0000, | |
SenderName : 0x0034, | |
FullMessage : 0x0065, | |
OnlyMessage : 0x0C1D, | |
ChannelNum : 0x17D8, | |
TimeStamp : 0x17E8 | |
} | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Constants // | |
//----------------------------------------------------------------------------// | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Player race enumeration constants | |
const PlayerRace = | |
{ | |
0 : "None", | |
1 : "Human", | |
2 : "Orc", | |
3 : "Dwarf", | |
4 : "NightElf", | |
5 : "Undead", | |
6 : "Tauren", | |
7 : "Gnome", | |
8 : "Troll", | |
9 : "Goblin", | |
10 : "BloodElf", | |
11 : "Draenei", | |
22 : "Worgen", | |
24 : "PandarenN", | |
25 : "PandarenA", | |
26 : "PandarenH" | |
}; | |
//////////////////////////////////////////////////////////////////////////////// | |
/// Player class enumeration constants | |
const PlayerClass = | |
{ | |
0 : "None", | |
1 : "Warrior", | |
2 : "Paladin", | |
3 : "Hunter", | |
4 : "Rogue", | |
5 : "Priest", | |
6 : "DeathKnight", | |
7 : "Shaman", | |
8 : "Mage", | |
9 : "Warlock", | |
10 : "Monk", | |
11 : "Druid" | |
}; | |
//----------------------------------------------------------------------------// | |
// Player Names // | |
//----------------------------------------------------------------------------// | |
// Used to retrieve player guid | |
let guidBuff = new Buffer (16); | |
// Create application controller | |
new (require ("./app_controller")) | |
(250, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
let entry = memory.readPtr | |
// Retrieve the first name cache entry | |
(module + offsets.NameCache.TableBase); | |
let names = [ ]; | |
let repeater = { }; | |
let infinite = 0; | |
// Read all entries from first to last | |
while (entry > 0 && (entry & 1) === 0) | |
{ | |
// Avoid repetition of entries | |
if (repeater[entry]) break; | |
else repeater[entry] = true; | |
// Avoid possible infinite loop | |
if (++infinite >= 20000) break; | |
names.push | |
({ | |
guid : memory.readData (entry + offsets.NameCache.Entry.Guid, guidBuff, 16) ? | |
guidBuff.toString ("hex").toUpperCase() : "", | |
name : memory.readString (entry + offsets.NameCache.Entry.Name, 80), | |
race : memory.readInt32 (entry + offsets.NameCache.Entry.Race ), | |
clazz: memory.readInt32 (entry + offsets.NameCache.Entry.Class ) | |
}); | |
// Read the next entry in table | |
entry = memory.readPtr (entry + | |
offsets.NameCache.EntryNext); | |
} | |
// Print each name | |
names.map (name => | |
{ | |
const race = PlayerRace [name.race ] || ""; | |
const clazz = PlayerClass[name.clazz] || ""; | |
console.log (`Name=${name.name} Race=${race} Class=${clazz}`); | |
}); | |
// All finished | |
process.exit(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
//----------------------------------------------------------------------------// | |
// Target Monitor // | |
//----------------------------------------------------------------------------// | |
// Used to retrieve player guid | |
let guidBuff = new Buffer (16); | |
// We need timer to calculate aura times | |
const Timer = require ("robot-js").Timer; | |
// Calculate time left and percentage info | |
function calculateCastTimes (player, now) | |
{ | |
const casting = player.casting || player.channel; | |
const castingStarted = player.castingStarted || player.channelStarted; | |
const castingWillEnd = player.castingWillEnd || player.channelWillEnd; | |
let timeleft = 0; | |
let percent = 0; | |
if (casting > 0 && | |
castingStarted > 0 && castingWillEnd > 0) | |
{ | |
timeleft = (castingWillEnd - now) / 1000; | |
percent = (now - castingStarted) / | |
(castingWillEnd - castingStarted) * 100; | |
if (timeleft < 0) timeleft = 0; | |
if (percent < 0) percent = 0; | |
if (percent > 100) percent = 100; | |
} | |
return { casting, timeleft, percent }; | |
} | |
// Create application controller | |
new (require ("./app_controller")) | |
(250, function (gameInstance) | |
{ | |
// Some shortcuts to update the game | |
const memory = gameInstance.memory; | |
const module = gameInstance.module; | |
const offsets = gameInstance.offsets; | |
const player = memory.readPtr | |
// Retrieve the player pointer | |
(module + offsets.LocalPlayer); | |
let entry = memory.readPtr | |
// Retrieve the entity list manager | |
(module + offsets.Entity.TableBase); | |
// Make sure player and entry are valid | |
if (player <= 0 || entry <= 0) return; | |
entry = memory.readPtr | |
// Retrieve the first entity entry | |
(entry + offsets.Entity.EntryFirst); | |
let players = [ ]; | |
let localGuid = ""; | |
let repeater = { }; | |
let infinite = 0; | |
// Read all entries from first to last | |
while (entry > 0 && (entry & 1) === 0) | |
{ | |
// Avoid repetition of entries | |
if (repeater[entry]) break; | |
else repeater[entry] = true; | |
// Avoid possible infinite loop | |
if (++infinite >= 20000) break; | |
// Retrieve type and descriptor | |
const type = memory.readInt32 (entry + offsets.Entity.Entry.Type ); | |
const desc = memory.readPtr (entry + offsets.Entity.Entry.Descriptors); | |
// Scan only player entities | |
if (desc > 0 && type === 4) | |
{ | |
const guid = memory.readData (desc + | |
offsets.Entity.Entry.Desc.GlobalID, guidBuff, 16) ? | |
guidBuff.toString ("hex").toUpperCase() : ""; | |
const target = memory.readData (entry + | |
offsets.Entity.Player.Target, guidBuff, 16) ? | |
guidBuff.toString ("hex").toUpperCase() : ""; | |
// Store local GUID | |
if (entry === player) | |
localGuid = guid; | |
players.push | |
({ | |
guid, target, | |
casting : memory.readInt32 (entry + offsets.Entity.Unit.Casting ), | |
castingStarted: memory.readInt32 (entry + offsets.Entity.Unit.CastingStarted), | |
castingWillEnd: memory.readInt32 (entry + offsets.Entity.Unit.CastingWillEnd), | |
channel : memory.readInt32 (entry + offsets.Entity.Unit.Channel ), | |
channelStarted: memory.readInt32 (entry + offsets.Entity.Unit.ChannelStarted), | |
channelWillEnd: memory.readInt32 (entry + offsets.Entity.Unit.ChannelWillEnd) | |
}); | |
} | |
// Read the next entry in table | |
entry = memory.readPtr (entry + | |
offsets.Entity.EntryNext); | |
} | |
// Cheap way to clear the screen | |
process.stdout.write ("\x1Bc"); | |
// Retrieve the current Cpu Time | |
const now = Timer.getCpuTime(); | |
console.log ("Targeting Me"); | |
// Print each player | |
players.map (player => | |
{ | |
if (player.target === localGuid) | |
{ | |
let times = calculateCastTimes (player, now); | |
console.log (`${player.guid} Casting=${times.casting} TimeLeft=${ | |
times.timeleft} Percent=${times.percent.toFixed (2)}`); | |
} | |
}); | |
console.log ("\nTargeting"); | |
// Print each player | |
players.map (player => | |
{ | |
let times = calculateCastTimes (player, now); | |
console.log (`${player.guid} -> ${player.target} Casting=${times.casting | |
} TimeLeft=${times.timeleft} Percent=${times.percent.toFixed (2)}`); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Error: Cannot find module './win32-x64-57'