-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
436 additions
and
205 deletions.
There are no files selected for viewing
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
132 changes: 132 additions & 0 deletions
132
definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package org.sinytra.adapter.patch; | ||
|
||
import com.mojang.logging.LogUtils; | ||
import it.unimi.dsi.fastutil.Pair; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.objectweb.asm.tree.ClassNode; | ||
import org.objectweb.asm.tree.MethodNode; | ||
import org.sinytra.adapter.patch.api.MethodContext; | ||
import org.sinytra.adapter.patch.api.PatchAuditTrail; | ||
import org.slf4j.Logger; | ||
|
||
import java.text.DecimalFormat; | ||
import java.util.ArrayList; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; | ||
|
||
public class PatchAuditTrailImpl implements PatchAuditTrail { | ||
private static final DecimalFormat FORMAT = new DecimalFormat("##.00"); | ||
private static final Logger LOGGER = LogUtils.getLogger(); | ||
private final Map<Candidate, AuditLog> auditTrail = new LinkedHashMap<>(); | ||
private final Map<Candidate, Match> candidates = new ConcurrentHashMap<>(); | ||
|
||
public void prepareMethod(MethodContext methodContext) { | ||
Candidate candidate = new Candidate(methodContext.getMixinClass(), methodContext.getMixinMethod()); | ||
synchronized (this.auditTrail) { | ||
this.auditTrail.put(candidate, AuditLog.create(methodContext)); | ||
} | ||
} | ||
|
||
public void recordAudit(Object transform, ClassNode classNode, String message, Object... args) { | ||
Candidate candidate = new Candidate(classNode, null); | ||
recordAudit(transform, null, candidate, message.formatted(args)); | ||
} | ||
|
||
public void recordAudit(Object transform, MethodContext methodContext, String message, Object... args) { | ||
Candidate candidate = new Candidate(methodContext.getMixinClass(), methodContext.getMixinMethod()); | ||
recordAudit(transform, methodContext.getMixinMethod(), candidate, message.formatted(args)); | ||
} | ||
|
||
private void recordAudit(Object transform, @Nullable MethodNode methodNode, Candidate candidate, String message) { | ||
synchronized (this.auditTrail) { | ||
AuditLog auditLog = this.auditTrail.computeIfAbsent(candidate, k -> new AuditLog(methodNode != null ? methodNode.name + methodNode.desc : null, new ArrayList<>())); | ||
List<Pair<Object, StringBuilder>> entries = auditLog.entries(); | ||
|
||
StringBuilder builder; | ||
if (entries.isEmpty() || entries.getLast().left() != transform) { | ||
entries.add(Pair.of(transform, builder = new StringBuilder())); | ||
builder.append("\n >> Using ").append(transform.getClass().getName()); | ||
} else { | ||
builder = entries.getLast().right(); | ||
} | ||
|
||
builder.append("\n - ").append(message); | ||
LOGGER.info(MIXINPATCH, "Applying [{}] {}", transform.getClass().getSimpleName(), message); | ||
} | ||
} | ||
|
||
public void recordResult(MethodContext methodContext, Match match) { | ||
Candidate candidate = new Candidate(methodContext.getMixinClass(), methodContext.getMixinMethod()); | ||
this.candidates.compute(candidate, (key, prev) -> prev == null ? match : prev.or(match)); | ||
} | ||
|
||
public String getCompleteReport() { | ||
StringBuilder builder = new StringBuilder(); | ||
|
||
getSummaryLines().forEach(l -> builder.append(l).append("\n")); | ||
|
||
List<Map.Entry<Candidate, Match>> failed = this.candidates.entrySet().stream().filter(m -> m.getValue() == Match.NONE).toList(); | ||
if (!failed.isEmpty()) { | ||
builder.append("\n=============== Failed mixins ==============="); | ||
failed.forEach(e -> builder.append("\n").append(e.getKey().classNode().name).append("\t").append(e.getKey().methodNode().name).append(e.getKey().methodNode().desc)); | ||
builder.append("\n=============================================\n\n"); | ||
} else { | ||
builder.append("\n"); | ||
} | ||
|
||
this.auditTrail.forEach((candidate, auditLog) -> { | ||
if (auditLog.entries().isEmpty()) { | ||
return; | ||
} | ||
|
||
if (auditLog.originalMethod() == null) { | ||
builder.append("Mixin class ").append(candidate.classNode().name); | ||
} else { | ||
builder.append("Mixin method ").append(candidate.classNode().name).append(" ").append(auditLog.originalMethod()); | ||
} | ||
|
||
for (Pair<Object, StringBuilder> record : auditLog.entries()) { | ||
builder.append(record.right()); | ||
} | ||
|
||
builder.append("\n\n"); | ||
}); | ||
|
||
return builder.toString(); | ||
} | ||
|
||
private List<String> getSummaryLines() { | ||
int total = this.candidates.size(); | ||
int successful = (int) this.candidates.values().stream().filter(m -> m == Match.FULL).count(); | ||
int partial = (int) this.candidates.values().stream().filter(m -> m == Match.PARTIAL).count(); | ||
int failed = (int) this.candidates.values().stream().filter(m -> m == Match.NONE).count(); | ||
double rate = (successful + partial) / (double) total * 100; | ||
double accuracy = (successful / (double) total + partial / (double) total / 2.0) * 100; | ||
|
||
return List.of( | ||
"==== Connector Mixin Patch Audit Summary ====", | ||
"Successful: %s".formatted(successful), | ||
"Partial: %s".formatted(partial), | ||
"Failed: %s".formatted(failed), | ||
"Success rate: %s%% Accuracy: %s%%".formatted(FORMAT.format(rate), FORMAT.format(accuracy)), | ||
"=============================================" | ||
); | ||
} | ||
|
||
public boolean hasFailingMixins() { | ||
return this.candidates.containsValue(Match.NONE); | ||
} | ||
|
||
record AuditLog(@Nullable String originalMethod, List<Pair<Object, StringBuilder>> entries) { | ||
public static AuditLog create(MethodContext methodContext) { | ||
return new AuditLog(methodContext.getMixinMethod().name + methodContext.getMixinMethod().desc, new ArrayList<>()); | ||
} | ||
} | ||
|
||
record Candidate(ClassNode classNode, MethodNode methodNode) { | ||
} | ||
} |
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
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
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
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
33 changes: 33 additions & 0 deletions
33
definition/src/main/java/org/sinytra/adapter/patch/api/PatchAuditTrail.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package org.sinytra.adapter.patch.api; | ||
|
||
import org.objectweb.asm.tree.ClassNode; | ||
|
||
public interface PatchAuditTrail { | ||
void prepareMethod(MethodContext methodContext); | ||
|
||
void recordAudit(Object transform, ClassNode classNode, String message, Object... args); | ||
|
||
void recordAudit(Object transform, MethodContext methodContext, String message, Object... args); | ||
|
||
void recordResult(MethodContext methodContext, Match match); | ||
|
||
String getCompleteReport(); | ||
|
||
boolean hasFailingMixins(); | ||
|
||
enum Match { | ||
NONE, | ||
PARTIAL, | ||
FULL; | ||
|
||
public Match or(Match other) { | ||
if (this == NONE && other != NONE) { | ||
return other; | ||
} | ||
if (this == PARTIAL && other == FULL) { | ||
return FULL; | ||
} | ||
return this; | ||
} | ||
} | ||
} |
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
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
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
Oops, something went wrong.