Arts with launch type 2 (buffs, auras, heals) are only valid on allies or without a target; with an enemy under the cursor the game dropped the order. Orders of a player hero for such arts lose a non-ally target, which casts them on the hero. The launch type comes from the art definition tables (game/engine/arts.h, tools/arttable.mjs). Also: skill keys check the relocated taskbar slots (all 7), Ghidra data labels (g_ names in names.txt). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
82 lines
3.2 KiB
Java
82 lines
3.2 KiB
Java
// Apply function names from tools/names.txt to the persistent sacred.exe
|
|
// Ghidra project.
|
|
//
|
|
// Headless usage (see tools/rename.ps1):
|
|
// analyzeHeadless <projectDir> sacred -process sacred.exe -noanalysis
|
|
// -scriptPath tools/ghidra -postScript Rename.java <namesFile>
|
|
//
|
|
// names.txt: one "0xADDRESS Name" per line, "Class::Method" puts the function
|
|
// into a class namespace; "#" starts a comment. Functions are created where
|
|
// none starts at the address yet. Names starting with "g_" label data
|
|
// (globals, tables) instead of functions.
|
|
// @category sacred_re
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
|
|
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
|
import ghidra.app.script.GhidraScript;
|
|
import ghidra.program.model.address.Address;
|
|
import ghidra.program.model.listing.Function;
|
|
import ghidra.program.model.symbol.Namespace;
|
|
import ghidra.program.model.symbol.SourceType;
|
|
import ghidra.program.model.symbol.SymbolTable;
|
|
|
|
public class Rename extends GhidraScript {
|
|
|
|
@Override
|
|
protected void run() throws Exception {
|
|
String[] args = getScriptArgs();
|
|
if (args.length != 1) {
|
|
printerr("usage: Rename.java <namesFile>");
|
|
return;
|
|
}
|
|
SymbolTable symbols = currentProgram.getSymbolTable();
|
|
int renamed = 0;
|
|
int labelled = 0;
|
|
for (String raw : Files.readAllLines(Paths.get(args[0]), StandardCharsets.UTF_8)) {
|
|
String line = raw.replaceAll("#.*", "").trim();
|
|
if (line.isEmpty()) {
|
|
continue;
|
|
}
|
|
String[] parts = line.split("\\s+");
|
|
if (parts.length != 2) {
|
|
printerr("bad line: " + raw);
|
|
continue;
|
|
}
|
|
Address address = toAddr(parts[0]);
|
|
if (parts[1].startsWith("g_")) {
|
|
createLabel(address, parts[1], true, SourceType.USER_DEFINED);
|
|
labelled++;
|
|
continue;
|
|
}
|
|
Function function = getFunctionAt(address);
|
|
if (function == null) {
|
|
new DisassembleCommand(address, null, true).applyTo(currentProgram, monitor);
|
|
function = createFunction(address, null);
|
|
}
|
|
if (function == null) {
|
|
printerr("no function at " + parts[0]);
|
|
continue;
|
|
}
|
|
String name = parts[1];
|
|
Namespace namespace = currentProgram.getGlobalNamespace();
|
|
int separator = name.lastIndexOf("::");
|
|
if (separator >= 0) {
|
|
String className = name.substring(0, separator);
|
|
name = name.substring(separator + 2);
|
|
namespace = symbols.getNamespace(className, currentProgram.getGlobalNamespace());
|
|
if (namespace == null) {
|
|
namespace = symbols.createClass(currentProgram.getGlobalNamespace(), className,
|
|
SourceType.USER_DEFINED);
|
|
}
|
|
}
|
|
function.setParentNamespace(namespace);
|
|
function.setName(name, SourceType.USER_DEFINED);
|
|
renamed++;
|
|
}
|
|
println("renamed " + renamed + " functions, labelled " + labelled + " data addresses");
|
|
}
|
|
}
|