Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,24 @@ public static void fillVersionFromJar(SimpleClassPath cp, McVersion.Builder buil
return;
}

CpEntry entry = cp.getEntry("net/minecraft/client/Minecraft.class");
CpEntry minecraft = cp.getEntry("net/minecraft/client/Minecraft.class");
CpEntry sharedConstants = cp.getEntry("net/minecraft/SharedConstants.class");

if (entry != null) {
if (minecraft != null) {
// version-like constant return value of a Minecraft method (obfuscated/unknown name)
if (fromAnalyzer(entry.getInputStream(), new MethodConstantRetVisitor(null), builder)) {
if (fromAnalyzer(minecraft.getInputStream(), new MethodConstantRetVisitor(null), builder)) {
return;
}

// version-like constant passed into Display.setTitle in a Minecraft method (obfuscated/unknown name)
if (fromAnalyzer(entry.getInputStream(), new MethodStringConstantContainsVisitor("org/lwjgl/opengl/Display", "setTitle"), builder)) {
if (fromAnalyzer(minecraft.getInputStream(), new MethodStringConstantContainsVisitor("org/lwjgl/opengl/Display", "setTitle"), builder)) {
return;
}
}

if (sharedConstants != null) {
// version constant set in SharedConstant's VERSION_STRING field (obfuscated/unknown name)
if (fromAnalyzer(sharedConstants.getInputStream(), new FieldNameVisitor("VERSION_STRING"), builder)) {
return;
}
}
Expand Down Expand Up @@ -684,6 +692,32 @@ protected void visitAnyInsn() {
private String result;
}

private static final class FieldNameVisitor extends ClassVisitor implements Analyzer {
FieldNameVisitor(String fieldName) {
super(FabricLoaderImpl.ASM_VERSION);

this.fieldName = fieldName;
}

@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if (name.equals(fieldName)) {
this.result = (String) value;
}

return super.visitField(access, name, descriptor, signature, value);
}

@Override
public String getResult() {
return this.result;
}


private final String fieldName;
private String result;
}

private static final class MethodConstantRetVisitor extends ClassVisitor implements Analyzer {
MethodConstantRetVisitor(String methodName) {
super(FabricLoaderImpl.ASM_VERSION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.ObjectShare;
import net.fabricmc.loader.api.VersionParsingException;
import net.fabricmc.loader.api.extension.ModMetadataBuilder.ModDependencyBuilder;
import net.fabricmc.loader.api.metadata.ModDependency;
import net.fabricmc.loader.impl.FabricLoaderImpl;
import net.fabricmc.loader.impl.FormattedException;
Expand All @@ -47,8 +48,8 @@
import net.fabricmc.loader.impl.game.minecraft.patch.EntrypointPatchFML125;
import net.fabricmc.loader.impl.game.patch.GameTransformer;
import net.fabricmc.loader.impl.launch.FabricLauncher;
import net.fabricmc.loader.impl.launch.MappingConfiguration;
import net.fabricmc.loader.impl.metadata.BuiltinModMetadata;
import net.fabricmc.loader.impl.metadata.ModDependencyImpl;
import net.fabricmc.loader.impl.util.Arguments;
import net.fabricmc.loader.impl.util.ExceptionUtil;
import net.fabricmc.loader.impl.util.LoaderUtil;
Expand Down Expand Up @@ -119,7 +120,9 @@ public Collection<BuiltinMod> getBuiltinMods() {
int version = versionData.getClassVersion().getAsInt() - 44;

try {
metadata.addDependency(new ModDependencyImpl(ModDependency.Kind.DEPENDS, "java", Collections.singletonList(String.format(Locale.ENGLISH, ">=%d", version))));
metadata.addDependency(ModDependencyBuilder.create(ModDependency.Kind.DEPENDS, "java")
.addVersion(String.format(Locale.ENGLISH, ">=%d", version))
.build());
} catch (VersionParsingException e) {
throw new RuntimeException(e);
}
Expand All @@ -146,19 +149,14 @@ public Path getLaunchDirectory() {
return getLaunchDirectory(arguments);
}

@Override
public boolean isObfuscated() {
return true; // generally yes...
}

@Override
public boolean requiresUrlClassLoader() {
return hasModLoader;
}

@Override
public boolean isEnabled() {
return System.getProperty(SystemProperties.SKIP_MC_PROVIDER) == null;
return !SystemProperties.isSet(SystemProperties.SKIP_MC_PROVIDER);
}

@Override
Expand Down Expand Up @@ -287,7 +285,10 @@ private static Path getLaunchDirectory(Arguments argMap) {
public void initialize(FabricLauncher launcher) {
launcher.setValidParentClassPath(validParentClassPath);

if (isObfuscated()) {
String gameNs = System.getProperty(SystemProperties.GAME_MAPPING_NAMESPACE);
if (gameNs == null) gameNs = launcher.isDevelopment() ? MappingConfiguration.NAMED_NAMESPACE : MappingConfiguration.OFFICIAL_NAMESPACE;

if (!gameNs.equals(launcher.getMappingConfiguration().getRuntimeNamespace())) { // game is obfuscated / in another namespace -> remap
Map<String, Path> obfJars = new HashMap<>(3);
String[] names = new String[gameJars.size()];

Expand All @@ -311,6 +312,7 @@ public void initialize(FabricLauncher launcher) {
}

obfJars = GameProviderHelper.deobfuscate(obfJars,
gameNs,
getGameId(), getNormalizedGameVersion(),
getLaunchDirectory(),
launcher);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ public abstract class FabricTweaker extends FabricLauncherBase implements ITweak
protected Arguments arguments;
private LaunchClassLoader launchClassLoader;
private final List<Path> classPath = new ArrayList<>();
private boolean isDevelopment;

@SuppressWarnings("unchecked")
private final boolean isPrimaryTweaker = ((List<ITweaker>) Launch.blackboard.get("Tweaks")).isEmpty();
Expand All @@ -76,12 +75,6 @@ public String getEntrypoint() {
return getLaunchTarget();
}

@Override
public String getTargetNamespace() {
// TODO: Won't work outside of Yarn
return isDevelopment ? "named" : "intermediary";
}

@Override
public void acceptOptions(List<String> localArgs, File gameDir, File assetsDir, String profile) {
arguments = new Arguments();
Expand All @@ -98,7 +91,6 @@ public void acceptOptions(List<String> localArgs, File gameDir, File assetsDir,

@Override
public void injectIntoClassLoader(LaunchClassLoader launchClassLoader) {
isDevelopment = Boolean.parseBoolean(System.getProperty(SystemProperties.DEVELOPMENT, "false"));
Launch.blackboard.put(SystemProperties.DEVELOPMENT, isDevelopment);
setProperties(Launch.blackboard);

Expand Down Expand Up @@ -143,15 +135,14 @@ private void init() {

arguments = null;

provider.initialize(this);

FabricLoaderImpl loader = FabricLoaderImpl.INSTANCE;
loader.setGameProvider(provider);
provider.initialize(this);
loader.load();
loader.freeze();

launchClassLoader.registerTransformer(FabricClassTransformer.class.getName());
FabricLoaderImpl.INSTANCE.loadAccessWideners();
FabricLoaderImpl.INSTANCE.loadClassTweakers();

// Setup Mixin environment
MixinBootstrap.init();
Expand Down Expand Up @@ -303,9 +294,4 @@ private byte[] toByteArray(InputStream inputStream) throws IOException {

return outputStream.toByteArray();
}

@Override
public boolean isDevelopment() {
return isDevelopment;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void process(FabricLauncher launcher, Function<String, ClassReader> class
throw new RuntimeException("Could not find main method in " + entrypoint + "!");
}

if (type == EnvType.CLIENT && mainMethod.instructions.size() < 10) {
if (type == EnvType.CLIENT && mainMethod.instructions.size() < 18) {
// 22w24+ forwards to another method in the same class instead of processing in main() directly, use that other method instead if that's the case
MethodInsnNode invocation = null;

Expand All @@ -108,13 +108,8 @@ public void process(FabricLauncher launcher, Function<String, ClassReader> class
if (invocation == null
&& insn.getType() == AbstractInsnNode.METHOD_INSN
&& (methodInsn = (MethodInsnNode) insn).owner.equals(mainClass.name)) {
// capture first method insn to the same class
// capture last method insn to the same class
invocation = methodInsn;
} else if (insn.getOpcode() > Opcodes.ALOAD // ignore constant and variable loads as well as NOP, labels and line numbers
&& insn.getOpcode() != Opcodes.RETURN) { // and RETURN
// found unexpected insn for a simple forwarding method
invocation = null;
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2016 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.loader.api.extension;

import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.tree.ClassNode;

import net.fabricmc.loader.api.metadata.ModDependency;
import net.fabricmc.loader.api.metadata.ModMetadata;

public interface LoaderExtensionApi { // one instance per extension, binding the caller mod id
void addPathToCacheKey(Path path);
void setExternalModSource(); // referenced loader extension must run every time, even if all cache keys match

ModCandidate readMod(Path path, /*@Nullable*/ String namespace);
ModCandidate readMod(List<Path> paths, /*@Nullable*/ String namespace);
ModCandidate createMod(List<Path> paths, ModMetadata metadata, Collection<ModCandidate> nestedMods);

Collection<ModCandidate> getMods(String modId);
Collection<ModCandidate> getMods();
boolean addMod(ModCandidate mod);
boolean removeMod(ModCandidate mod);

void addModSource(Function<ModDependency, ModCandidate> source);

void addToClassPath(Path path);
// TODO: add a way to add virtual resources (name + content) and classes

void addMixinConfig(ModCandidate mod, String location);

void addClassByteBufferTransformer(ClassTransformer<ByteBuffer> transformer, String phase);
void addClassVisitorProvider(ClassTransformer<ClassVisitor> provider, String phase);
void addClassNodeTransformer(ClassTransformer<ClassNode> transformer, String phase);

interface ClassTransformer<T> {
String getName(); // name further identifying the transformer within the context mod
boolean appliesTo(String internalName, /*@Nullable*/ URL source);
/*@Nullable*/ T apply(String internalName, /*@Nullable*/ T input); // may reuse input!
}

// TODO: resource transformers
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2016 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.loader.api.extension;

@FunctionalInterface
public interface LoaderExtensionEntrypoint {
void initExtension(LoaderExtensionApi api);
}
43 changes: 43 additions & 0 deletions src/main/java/net/fabricmc/loader/api/extension/ModCandidate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2016 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.fabricmc.loader.api.extension;

import java.nio.file.Path;
import java.util.Collection;
import java.util.List;

import net.fabricmc.loader.api.Version;
import net.fabricmc.loader.api.metadata.ModMetadata;

/**
* Representation of a mod that might get chosen to be loaded.
*
* <p>The data exposed here is read only, mutating it is not supported!
*/
public interface ModCandidate {
ModMetadata getMetadata();
String getId();
Version getVersion();

boolean hasPath();
List<Path> getPaths();
String getLocalPath();

boolean isRoot();
Collection<? extends ModCandidate> getContainingMods();
Collection<? extends ModCandidate> getContainedMods();
}
Loading