新增按钮 +10 Red Bones:在当前选中骨骼下用编辑器自己的 New Bone 建 10 根,位置随机(±200),颜色写 red(Gp 的 x/y 走 names.tsv 反查、color 按类型找字段)
This commit is contained in:
1 parent
2e325bc1b9
commit
f696c15671
1 file changed
+137
-11
@@ -129,9 +129,11 @@ public final class ObjectPanel {
|
|||||||
Object rename = button(loader, skin, "Rename");
|
Object rename = button(loader, skin, "Rename");
|
||||||
Object inspect = button(loader, skin, "Inspect");
|
Object inspect = button(loader, skin, "Inspect");
|
||||||
Object setValue = button(loader, skin, "Set Value");
|
Object setValue = button(loader, skin, "Set Value");
|
||||||
|
Object addTen = button(loader, skin, "+10 Red Bones");
|
||||||
|
|
||||||
// 按钮直接放进根表格:两行按钮 + 一行滚动列表(与阶段四验证过的结构一致)
|
// 按钮直接放进根表格:两行按钮 + 一行滚动列表(与阶段四验证过的结构一致)
|
||||||
Object[] top = {refresh, newBone, newSlot, newBBox, newPath, delete, rename, inspect, setValue};
|
Object[] top = {refresh, newBone, newSlot, newBBox, newPath, delete, rename, inspect, setValue,
|
||||||
|
addTen};
|
||||||
Object buttons = tableClass.getConstructor().newInstance();
|
Object buttons = tableClass.getConstructor().newInstance();
|
||||||
call(buttons, Obf.TABLE_TOP, new Class<?>[0], tableClass);
|
call(buttons, Obf.TABLE_TOP, new Class<?>[0], tableClass);
|
||||||
call(buttons, Obf.TABLE_LEFT, new Class<?>[0], tableClass); // 按钮块靠左上(不然整宽后会居中)
|
call(buttons, Obf.TABLE_LEFT, new Class<?>[0], tableClass); // 按钮块靠左上(不然整宽后会居中)
|
||||||
@@ -181,6 +183,12 @@ public final class ObjectPanel {
|
|||||||
System.err.println("[panel] 设置中段高度失败: " + error);
|
System.err.println("[panel] 设置中段高度失败: " + error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wire(loader, addTen, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
createTenRedBones(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
wire(loader, setValue, new Runnable() {
|
wire(loader, setValue, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -618,6 +626,109 @@ public final class ObjectPanel {
|
|||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在当前选中的骨骼下新建 10 根骨骼:位置随机、颜色红色。
|
||||||
|
* 建用编辑器自己的 New Bone(带撤销),建完立刻改该骨骼的 x/y 与 color 字段。
|
||||||
|
*/
|
||||||
|
private static void createTenRedBones(final State state) {
|
||||||
|
SceneActions.onEditorThread(state.loader, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Object parent = state.target;
|
||||||
|
if (parent == null) {
|
||||||
|
setStatus(state, "+10 Red Bones: select a parent bone first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Class<?> colorClass = Class.forName("com.badlogic.gdx.graphics.Color", true, state.loader);
|
||||||
|
Object red = colorClass.getConstructor(float.class, float.class, float.class,
|
||||||
|
float.class).newInstance(Float.valueOf(1f), Float.valueOf(0f), Float.valueOf(0f),
|
||||||
|
Float.valueOf(1f));
|
||||||
|
int made = 0;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
java.util.List<Object> before = SceneObjects.listAllNodes(state.loader);
|
||||||
|
SceneActions.create(state.loader, parent, "Bone");
|
||||||
|
Object fresh = firstNew(before, SceneObjects.listAllNodes(state.loader));
|
||||||
|
if (fresh == null) continue;
|
||||||
|
float x = (float) (Math.random() * 400.0 - 200.0);
|
||||||
|
float y = (float) (Math.random() * 400.0 - 200.0);
|
||||||
|
setBoneNumber(fresh, "x", x);
|
||||||
|
setBoneNumber(fresh, "y", y);
|
||||||
|
setBoneColor(fresh, red);
|
||||||
|
made++;
|
||||||
|
}
|
||||||
|
setStatus(state, "made " + made + " red bones under " + SceneObjects.nameOf(parent));
|
||||||
|
} catch (Throwable error) {
|
||||||
|
setStatus(state, "+10 Red Bones failed: " + error);
|
||||||
|
error.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
refreshList(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 前后列表对比,取第一个新出现的对象。 */
|
||||||
|
private static Object firstNew(java.util.List<Object> before, java.util.List<Object> after) {
|
||||||
|
for (Object item : after) {
|
||||||
|
boolean seen = false;
|
||||||
|
for (Object old : before) {
|
||||||
|
if (old == item) {
|
||||||
|
seen = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!seen) return item;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按"真名"(x/y/rotation…)改骨骼上的 float 字段:真名→混淆名走 names.tsv。 */
|
||||||
|
private static void setBoneNumber(Object bone, String realName, float value) {
|
||||||
|
try {
|
||||||
|
String obf = obfNameOf("Gp", "F", realName);
|
||||||
|
if (obf == null) return;
|
||||||
|
for (Class<?> type = bone.getClass(); type != null && type != Object.class;
|
||||||
|
type = type.getSuperclass()) {
|
||||||
|
for (java.lang.reflect.Field field : type.getDeclaredFields()) {
|
||||||
|
if (!field.getName().equals(obf) || field.getType() != float.class) continue;
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.setFloat(bone, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable error) {
|
||||||
|
System.err.println("[panel] 设置 " + realName + " 失败: " + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 骨骼颜色:找类型是 libGDX Color 的字段写进去。 */
|
||||||
|
private static void setBoneColor(Object bone, Object color) {
|
||||||
|
try {
|
||||||
|
for (Class<?> type = bone.getClass(); type != null && type != Object.class;
|
||||||
|
type = type.getSuperclass()) {
|
||||||
|
for (java.lang.reflect.Field field : type.getDeclaredFields()) {
|
||||||
|
if (!field.getType().getName().equals("com.badlogic.gdx.graphics.Color")) continue;
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(bone, color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable error) {
|
||||||
|
System.err.println("[panel] 设置颜色失败: " + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 映射表反查:owner + 描述符 + 真名 → 混淆名。 */
|
||||||
|
private static String obfNameOf(String owner, String desc, String realName) {
|
||||||
|
loadNames();
|
||||||
|
for (java.util.Map.Entry<String, String> entry : NAMES.entrySet()) {
|
||||||
|
if (!entry.getValue().equals(realName)) continue;
|
||||||
|
String[] parts = entry.getKey().split("#");
|
||||||
|
if (parts.length == 3 && parts[0].equals(owner) && parts[2].equals(desc)) return parts[1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static int countFields(Object object) {
|
private static int countFields(Object object) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (Class<?> type = object.getClass(); type != null && type != Object.class;
|
for (Class<?> type = object.getClass(); type != null && type != Object.class;
|
||||||
@@ -1261,16 +1372,31 @@ public final class ObjectPanel {
|
|||||||
StringBuilder out = new StringBuilder();
|
StringBuilder out = new StringBuilder();
|
||||||
out.append("buttons: ").append(buttonLabels()).append('\n');
|
out.append("buttons: ").append(buttonLabels()).append('\n');
|
||||||
press(0, out); // Refresh
|
press(0, out); // Refresh
|
||||||
out.append("after Refresh: ").append(rows(loader)).append('\n');
|
// 直接"选中 bone3 当父级"(列表行的标签取不到,就程序化选中)
|
||||||
// 列表是 Refresh 之后才建出来的,找到 "bone bone3" 那一行并按它
|
press(9, out); // +10 Red Bones(未选父级时应提示)
|
||||||
press(panelButton("bone bone3"), "row bone bone3", out);
|
sleepQuiet(1000);
|
||||||
out.append("after select: ").append(rows(loader)).append('\n');
|
Object parent = null;
|
||||||
press(2, out); // New Slot(会弹输入框,看面板能不能自己填+点 OK)
|
try {
|
||||||
sleepQuiet(3000);
|
parent = SceneActions.findByName(loader, "bone3");
|
||||||
out.append("after New Slot: ").append(rows(loader)).append('\n');
|
} catch (Throwable error) {
|
||||||
press(3, out); // New BBox
|
out.append("find bone3 failed: ").append(error).append('\n');
|
||||||
sleepQuiet(3000);
|
}
|
||||||
out.append("after New BBox: ").append(rows(loader)).append('\n');
|
out.append("parent = ").append(parent == null ? "null" : SceneObjects.nameOf(parent)).append('\n');
|
||||||
|
if (parent != null) {
|
||||||
|
final Object target = parent;
|
||||||
|
SceneActions.onEditorThread(loader, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
SceneActions.select(loader, target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 让 state.target 记住它(正常是点列表行设置的)
|
||||||
|
Object st = LAST_STATE;
|
||||||
|
if (st instanceof State) ((State) st).target = parent;
|
||||||
|
}
|
||||||
|
press(9, out); // 现在应当真的建 10 根
|
||||||
|
sleepQuiet(4000);
|
||||||
|
out.append("after +10 Red Bones: ").append(rows(loader)).append('\n');
|
||||||
return out.toString();
|
return out.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user