diff --git a/minecraft/.gitignore b/minecraft/.gitignore index a4c6e69be..896c508ad 100644 --- a/minecraft/.gitignore +++ b/minecraft/.gitignore @@ -3,5 +3,6 @@ !/build.gradle !/.gitignore +!/1.11 !/1.8 !/1.7 diff --git a/minecraft/1.11/.gitignore b/minecraft/1.11/.gitignore new file mode 100644 index 000000000..85be317cb --- /dev/null +++ b/minecraft/1.11/.gitignore @@ -0,0 +1,17 @@ +# Ignore All +/* + +# Sources +!/src + +# github +!/.gitignore +!/README.md + +# gradle +!/build.gradle +!/build.properties +!/settings.gradle +!/gradle.properties +!/gradlew* +!/gradle diff --git a/minecraft/1.11/build.gradle b/minecraft/1.11/build.gradle new file mode 100644 index 000000000..e4c6fdf32 --- /dev/null +++ b/minecraft/1.11/build.gradle @@ -0,0 +1,135 @@ +apply from: "https://raw.githubusercontent.com/NOVA-Team/NOVA-Gradle/master/shared-scripts/java.gradle" + +apply plugin: "com.jfrog.artifactory" +apply plugin: "com.github.johnrengelman.shadow" +apply plugin: "maven-publish" + +idea.module.name = "Core-MC-1.11" +archivesBaseName = "NOVA-Core-Wrapper-MC1.11" + +configurations { + fatJar + compile.extendsFrom fatJar +} + +dependencies { + fatJar project(":") + testCompile project(path: ':', configuration: 'wrapperTests') + + testCompile "junit:junit:4.12" + testCompile 'org.assertj:assertj-core:3.0.0' + testRuntime 'org.slf4j:slf4j-simple:1.7.10' +} + +jar { + manifest { + attributes 'FMLCorePlugin': 'nova.core.wrapper.mc.forge.v1_11.NovaMinecraftCore' + attributes 'FMLCorePluginContainsFMLMod': 'true' + attributes 'FMLAT': 'nova_at.cfg' + } +} + +task deobfJar(type: Jar) { + from sourceSets.main.output + classifier = 'deobf' + manifest { + attributes 'FMLCorePlugin': 'nova.core.wrapper.mc.forge.v1_11.NovaMinecraftCore' + attributes 'FMLCorePluginContainsFMLMod': 'true' + attributes 'FMLAT': 'nova_at.cfg' + } +} + +/** + * Create fat jar file with all dependencies included. + */ +task fatJar(type: Jar) { + configurations.fatJar.each {dep -> + from(project.zipTree(dep)) { + exclude 'META-INF', 'META-INF/**' + } + } + with jar + + manifest { + attributes 'FMLCorePlugin': 'nova.core.wrapper.mc.forge.v1_11.NovaMinecraftCore' + attributes 'FMLCorePluginContainsFMLMod': 'true' + attributes 'FMLAT': 'nova_at.cfg' + } + classifier = 'fat' +} + +artifacts { + archives deobfJar + archives fatJar +} + +publishing { + publications { + main(MavenPublication) { + from components.java + + artifactId archivesBaseName + + artifact sourcesJar + artifact javadocJar + artifact deobfJar + artifact fatJar + + pom.withXml(writePom(project.properties)) + pom.withXml {xml -> + def children = xml.asNode().get("dependencies")[0] + for (child in children) { + def artifactId = child.get("artifactId")[0].value()[0] + if (artifactId.equals("forgeSrc") || artifactId.equals("forgeBin")) { + children.remove(child) + break; + } + } + } + } + } +} + +artifactory { + publish { + defaults { + publications("main") + publishPom = true + } + } +} + +apply plugin: 'net.minecraftforge.gradle.forge' + +minecraft { + version = property("minecraft.version") + "-" + property("forge.version") + mappings = 'snapshot_20161220' + runDir = "run" +} + +reobf { + // TODO Figure out how to make this work with maven-publish (creates a new task 'reobfFatJar' that isn't compatible with maven-publish) + fatJar {classpath += configurations.compile} +} + +runClient { + jvmArgs '-Dfml.coreMods.load=nova.core.wrapper.mc.forge.v1_11.NovaMinecraftCore' +} + +runServer { + jvmArgs '-Dfml.coreMods.load=nova.core.wrapper.mc.forge.v1_11.NovaMinecraftCore' +} + +processResources { + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + expand 'version': project.version, 'mcversion': project.minecraft.version + } + + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } +} diff --git a/minecraft/1.11/gradle.properties b/minecraft/1.11/gradle.properties new file mode 100644 index 000000000..3d511bebd --- /dev/null +++ b/minecraft/1.11/gradle.properties @@ -0,0 +1,10 @@ +group = nova.core + +minecraft.version = 1.11 +forge.version = 13.19.1.2189 +forgeGradleVersion = 2.2-SNAPSHOT + +packaging = jar +info.inceptionYear = 2016 +info.description = The wrapper of the Nova API to the MinecraftForge 1.11 modding system. +info.organization.name = NOVA diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/NovaMinecraftCore.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/NovaMinecraftCore.java new file mode 100644 index 000000000..ac9c77799 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/NovaMinecraftCore.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11; + +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.MCVersion; +import nova.core.wrapper.mc.forge.v1_11.asm.transformers.Transformers; + +import java.util.Map; + +@MCVersion(value = "1.11") +public class NovaMinecraftCore implements IFMLLoadingPlugin { + @Override + public String[] getASMTransformerClass() { + return new String[] { Transformers.class.getName() }; + } + + @Override + public String getModContainerClass() { + return "nova.core.wrapper.mc.forge.v1_11.NovaMinecraftPreloader"; + } + + @Override + public String getSetupClass() { + return null; + } + + @Override + public void injectData(Map data) { + + } + + @Override + public String getAccessTransformerClass() { + return null; + } +} \ No newline at end of file diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/NovaMinecraftPreloader.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/NovaMinecraftPreloader.java new file mode 100644 index 000000000..a3aee5cf0 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/NovaMinecraftPreloader.java @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.minecraft.client.resources.AbstractResourcePack; +import net.minecraft.client.resources.FileResourcePack; +import net.minecraft.client.resources.IResourcePack; +import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraftforge.fml.client.FMLClientHandler; +import net.minecraftforge.fml.common.DummyModContainer; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.LoadController; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.ModMetadata; +import net.minecraftforge.fml.common.discovery.ASMDataTable; +import net.minecraftforge.fml.common.event.FMLConstructionEvent; +import net.minecraftforge.fml.relauncher.FMLLaunchHandler; +import net.minecraftforge.fml.relauncher.Side; +import nova.core.loader.Mod; +import nova.core.util.ClassLoaderUtil; +import nova.core.wrapper.mc.forge.v1_11.render.NovaFolderResourcePack; +import nova.core.wrapper.mc.forge.v1_11.render.NovaResourcePack; +import nova.core.wrapper.mc.forge.v1_11.util.ReflectionUtil; + +import java.io.File; +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class NovaMinecraftPreloader extends DummyModContainer { + public static final String version = "0.0.1"; + private static final ModMetadata md; + public static Set> modClasses; + public static Map, File> modClassToFile; + + static { + md = new ModMetadata(); + md.modId = "novapreloader"; + md.name = "NOVA Preloader"; + md.version = version; + } + + public NovaMinecraftPreloader() { + super(md); + } + + /** + * Dynamically generates a sound JSON file based on a resource pack's file structure. + * + * If it's a folder, then load it as a sound collection. + * A sound collection falls under the same resource name. When called to play, it will pick a random sound from the collection to play it. + * + * If it's just a sound file, then load the sound file + */ + public static String generateSoundJSON(AbstractResourcePack pack) { + JsonObject fakeSoundJSON = new JsonObject(); + + for (String domain : pack.getResourceDomains()) { + + if (pack instanceof FileResourcePack) { + //For zip resource packs + try { + ZipFile zipFile = new ZipFile(pack.resourcePackFile); + + if (zipFile.getEntry("assets/" + domain + "/sounds/") != null) { + Enumeration zipEntries = zipFile.entries(); + + while (zipEntries.hasMoreElements()) { + String zipPath = zipEntries.nextElement().getName(); + + String prefix = "assets/" + domain + "/sounds/"; + if (zipPath.startsWith(prefix) && !zipPath.equals(prefix)) { + String soundName = zipPath.replaceFirst(prefix, "").replaceFirst("[.][^.]+$", ""); + ZipEntry entry = zipFile.getEntry(zipPath); + + if (!soundName.contains("/")) { + JsonObject sound = new JsonObject(); + sound.addProperty("category", "ambient"); + JsonArray sounds = new JsonArray(); + + if (entry.isDirectory()) { + //Sound Collection + Enumeration zipEntries2 = zipFile.entries(); + while (zipEntries2.hasMoreElements()) { + String zipPath2 = zipEntries2.nextElement().getName(); + + if (zipPath2.startsWith(prefix + soundName + "/") && !zipFile.getEntry(zipPath2).isDirectory()) { + String randomSoundName = zipPath2.replaceFirst(prefix + soundName + "/", ""); + sounds.add(new JsonPrimitive(soundName + "/" + randomSoundName.replaceFirst("[.][^.]+$", ""))); + } + } + } else { + sounds.add(new JsonPrimitive(soundName)); + } + sound.add("sounds", sounds); + fakeSoundJSON.add(soundName, sound); + } + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + throw new ExceptionInInitializerError("Error generating fake sound JSON file."); + } + } else { + //For folder resource packs + //Load all sounds in the assets/domain/sounds/* + File folder = new File(pack.resourcePackFile, "assets/" + domain + "/sounds/"); + + if (folder.exists()) { + File[] listOfFiles = folder.listFiles(); + + for (File listedFile : listOfFiles) { + JsonObject sound = new JsonObject(); + sound.addProperty("category", "ambient"); + JsonArray sounds = new JsonArray(); + + String listedName = listedFile.getName().replaceFirst("[.][^.]+$", ""); + if (listedFile.isFile()) { + sounds.add(new JsonPrimitive(listedName)); + } else if (listedFile.isDirectory()) { + for (File soundItemFile : listedFile.listFiles()) + sounds.add(new JsonPrimitive(listedName + "/" + soundItemFile.getName().replaceFirst("[.][^.]+$", ""))); + } + + sound.add("sounds", sounds); + fakeSoundJSON.add(listedName, sound); + } + } + } + } + + return fakeSoundJSON.toString(); + } + + public static String generatePackMcmeta() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("description", "NOVA mod resource pack"); + jsonObject.addProperty("pack_format", "1"); + JsonObject outerObj = new JsonObject(); + outerObj.add("pack", jsonObject); + return outerObj.toString(); + } + + @Override + public boolean registerBus(EventBus bus, LoadController controller) { + bus.register(this); + return true; + } + + @Subscribe + public void load(FMLConstructionEvent event) { + try { + //TODO: Use AT + //Apache Commons Hack + Field launchHandlerField = FMLLaunchHandler.class.getDeclaredField("INSTANCE"); + launchHandlerField.setAccessible(true); + FMLLaunchHandler launchHandler = (FMLLaunchHandler) launchHandlerField.get(null); + Field clField = FMLLaunchHandler.class.getDeclaredField("classLoader"); + clField.setAccessible(true); + LaunchClassLoader classLoader = (LaunchClassLoader) clField.get(launchHandler); + //Obfuscation? + Field setField = LaunchClassLoader.class.getDeclaredField("classLoaderExceptions"); + setField.setAccessible(true); + Set classLoaderExceptions = (Set) setField.get(classLoader); + classLoaderExceptions.remove("org.apache."); + System.out.println("Successfully hacked 'org.apache' out of launcher exclusion"); + } catch (Exception e) { + throw new ClassLoaderUtil.ClassLoaderException(e); + } + + // Scan mod classes + ASMDataTable asmData = event.getASMHarvestedData(); + + modClassToFile = new HashMap<>(); + modClasses = asmData + .getAll(Mod.class.getName()) + .stream() + .map(ASMDataTable.ASMData::getClassName) + .map(c -> { + try { + return Class.forName(c); + } catch (ClassNotFoundException e) { + throw new ExceptionInInitializerError(e); + } + }) + .collect(Collectors.toSet()); + + //Inject fake mod containers into FML + List fmlMods = ReflectionUtil.getPrivateObject(Loader.instance(), "mods"); + List newMods = new ArrayList<>(); + newMods.addAll(fmlMods); + modClasses.forEach(mod -> { + ModMetadata fakeMeta = new ModMetadata(); + Mod annotation = mod.getAnnotation(Mod.class); + fakeMeta.modId = annotation.id(); + fakeMeta.name = annotation.name(); + fakeMeta.version = annotation.version(); + fakeMeta.description = annotation.description(); + newMods.add(new DummyNovaMod(fakeMeta, mod)); + }); + //TODO: Use AT + ReflectionUtil.setPrivateObject(Loader.instance(), newMods, "mods"); + + // Register resource packs + if (FMLCommonHandler.instance().getEffectiveSide() == Side.CLIENT) { + registerResourcePacks(); + } + } + + public void registerResourcePacks() { + Map> classesMap = modClasses + .stream() + .filter(clazz -> clazz.getAnnotation(Mod.class) != null) + .collect(Collectors.toMap((clazz) -> clazz.getAnnotation(Mod.class), Function.identity())); + + try { + // The same list exists in the Minecraft class, but that can be SRG or not. + // Reflecting FML is just less work for us. (Minecraft.field_110449_ao) + Field resourcePackField = FMLClientHandler.class.getDeclaredField("resourcePackList"); + resourcePackField.setAccessible(true); + List packs = (List) resourcePackField.get(FMLClientHandler.instance()); + + Set addedPacks = new HashSet<>(); + + classesMap.keySet().forEach(novaMod -> { + Class c = classesMap.get(novaMod); + + //Add jar resource pack + String fn = c.getProtectionDomain().getCodeSource().getLocation().toExternalForm(); + + if (fn.contains("!")) { + fn = fn.substring(0, fn.indexOf('!')).replaceFirst("jar:", ""); + File file; + try { + file = new File(new URL(fn).toURI()); + } catch (MalformedURLException | URISyntaxException e) { + file = new File(fn); //This will probably not work on Windows, but we can at least try + } + modClassToFile.put(c, file); + + if (!addedPacks.contains(fn)) { + addedPacks.add(fn); + packs.add(new NovaResourcePack(file, novaMod.id(), novaMod.domains())); + System.out.println("Registered NOVA jar resource pack: " + fn); + } + } else { + //Add folder resource pack location. The folderLocation is the root of the project, including the packages of classes, and an assets folder inside. + String folderLocation = c.getProtectionDomain().getCodeSource().getLocation().getPath(); + String classPath = c.getCanonicalName().replaceAll("\\.", "/"); + folderLocation = folderLocation.replaceFirst("file:", "").replace(classPath, "").replace("/.class", "").replaceAll("%20", " "); + File folderFile = new File(folderLocation); + if (!new File(folderFile, "assets").isDirectory()) { + //Try IDEA workaround. + folderFile = new File(folderLocation.replaceAll("build[\\\\/]classes", "build/resources")); + folderFile = new File(folderFile, "assets").isDirectory() ? folderFile : new File(folderLocation); + } + modClassToFile.put(c, folderFile); + + addedPacks.add(folderLocation); + packs.add(new NovaFolderResourcePack(folderFile, novaMod.id(), novaMod.domains())); + System.out.println("Registered NOVA folder resource pack: " + folderFile.getAbsolutePath()); + } + }); + resourcePackField.set(FMLClientHandler.instance(), packs); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * A fake NovaMod to inject into FML. + */ + private static class DummyNovaMod extends DummyModContainer { + private final Class mod; + private File source = null; + + public DummyNovaMod(ModMetadata meta, Class mod) { + super(meta); + this.mod = mod; + } + + @Override + public File getSource() { + if (this.source == null) { + this.source = NovaMinecraftPreloader.modClassToFile.get(mod); + } + return this.source; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/StaticForwarder.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/StaticForwarder.java new file mode 100644 index 000000000..43dc0a3e9 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/StaticForwarder.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import nova.core.event.BlockEvent; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWTileLoader; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * Static forwarder forwards injected methods. + * @author Calclavia + */ +public class StaticForwarder { + + public static void chunkSetBlockEvent(Chunk chunk, BlockPos pos, IBlockState oldBlockState, IBlockState newBlockState) { + // Publish the event + Game.events().publish( + new BlockEvent.Change( + Game.natives().toNova(chunk.getWorld()), + new Vector3D((chunk.xPosition << 4) + pos.getX(), pos.getY(), (chunk.zPosition << 4) + pos.getZ()), + Game.natives().toNova(oldBlockState.getBlock()), Game.natives().toNova(newBlockState.getBlock()) + ) + ); + } + + /** + * Used to inject forwarded TileEntites + * @param data + * @param clazz + * @return + * @throws Exception + */ + public static TileEntity loadTileEntityHook(World world, NBTTagCompound data, Class clazz) throws Exception { + if (FWTile.class.isAssignableFrom(clazz)) { + return FWTileLoader.loadTile(data); + } else { + return clazz.newInstance(); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ASMHelper.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ASMHelper.java new file mode 100644 index 000000000..956054244 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ASMHelper.java @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import net.minecraft.launchwrapper.LaunchClassLoader; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TryCatchBlockNode; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.objectweb.asm.Opcodes.ARETURN; +import static org.objectweb.asm.Opcodes.DRETURN; +import static org.objectweb.asm.Opcodes.FRETURN; +import static org.objectweb.asm.Opcodes.IRETURN; +import static org.objectweb.asm.Opcodes.LRETURN; +import static org.objectweb.asm.Opcodes.RET; +import static org.objectweb.asm.Opcodes.RETURN; + +/** + * @author ChickenBones + */ +public class ASMHelper { + public static LaunchClassLoader cl = (LaunchClassLoader) ASMHelper.class.getClassLoader(); + private static Method defineClass1; + private static Method defineClass2; + + static { + try { + defineClass1 = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class }); + defineClass2 = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class, ProtectionDomain.class }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static MethodNode findMethod(ObfMapping methodmap, ClassNode cnode) { + for (MethodNode mnode : cnode.methods) { + if (methodmap.matches(mnode)) { + return mnode; + } + } + return null; + } + + public static FieldNode findField(ObfMapping fieldmap, ClassNode cnode) { + for (FieldNode fnode : cnode.fields) { + if (fieldmap.matches(fnode)) { + return fnode; + } + } + return null; + } + + public static ClassNode createClassNode(byte[] bytes) { + return createClassNode(bytes, 0); + } + + public static ClassNode createClassNode(byte[] bytes, int flags) { + ClassNode cnode = new ClassNode(); + ClassReader reader = new ClassReader(bytes); + reader.accept(cnode, flags); + return cnode; + } + + public static byte[] createBytes(ClassNode cnode, int flags) { + ClassWriter cw = new CC_ClassWriter(flags); + cnode.accept(cw); + return cw.toByteArray(); + } + + public static byte[] writeMethods(String name, byte[] bytes, Multimap writers) { + if (writers.containsKey(name)) { + ClassNode cnode = createClassNode(bytes); + + for (MethodWriter mw : writers.get(name)) { + MethodNode mv = findMethod(mw.method, cnode); + if (mv == null) { + mv = (MethodNode) cnode.visitMethod(mw.access, mw.method.s_name, mw.method.s_desc, null, mw.exceptions); + } + + mv.access = mw.access; + mv.instructions.clear(); + mw.write(mv); + } + + bytes = createBytes(cnode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + } + return bytes; + } + + public static byte[] injectMethods(String name, byte[] bytes, Multimap injectors) { + if (injectors.containsKey(name)) { + ClassNode cnode = createClassNode(bytes); + + for (MethodInjector injector : injectors.get(name)) { + MethodNode method = findMethod(injector.method, cnode); + if (method == null) { + throw new RuntimeException("Method not found: " + injector.method); + } + System.out.println("Injecting into " + injector.method + "\n" + printInsnList(injector.injection)); + + List callNodes; + if (injector.before) { + callNodes = InstructionComparator.insnListFindStart(method.instructions, injector.needle); + } else { + callNodes = InstructionComparator.insnListFindEnd(method.instructions, injector.needle); + } + + if (callNodes.size() == 0) { + throw new RuntimeException("Needle not found in Haystack: " + injector.method + "\n" + printInsnList(injector.needle)); + } + + for (AbstractInsnNode node : callNodes) { + if (injector.before) { + System.out.println("Injected before: " + printInsn(node)); + method.instructions.insertBefore(node, cloneInsnList(injector.injection)); + } else { + System.out.println("Injected after: " + printInsn(node)); + method.instructions.insert(node, cloneInsnList(injector.injection)); + } + } + } + + bytes = createBytes(cnode, ClassWriter.COMPUTE_FRAMES); + } + return bytes; + } + + public static String printInsnList(InsnList list) { + InsnListPrinter p = new InsnListPrinter(); + p.visitInsnList(list); + return p.textString(); + } + + public static String printInsn(AbstractInsnNode insn) { + InsnListPrinter p = new InsnListPrinter(); + p.visitInsn(insn); + return p.textString(); + } + + public static Map cloneLabels(InsnList insns) { + HashMap labelMap = new HashMap(); + for (AbstractInsnNode insn = insns.getFirst(); insn != null; insn = insn.getNext()) { + if (insn.getType() == 8) { + labelMap.put((LabelNode) insn, new LabelNode()); + } + } + return labelMap; + } + + public static InsnList cloneInsnList(InsnList insns) { + return cloneInsnList(cloneLabels(insns), insns); + } + + public static InsnList cloneInsnList(Map labelMap, InsnList insns) { + InsnList clone = new InsnList(); + for (AbstractInsnNode insn = insns.getFirst(); insn != null; insn = insn.getNext()) { + clone.add(insn.clone(labelMap)); + } + + return clone; + } + + public static List cloneTryCatchBlocks(Map labelMap, List tcblocks) { + ArrayList clone = new ArrayList(); + for (TryCatchBlockNode node : tcblocks) { + clone.add(new TryCatchBlockNode(labelMap.get(node.start), labelMap.get(node.end), labelMap.get(node.handler), node.type)); + } + + return clone; + } + + public static List cloneLocals(Map labelMap, List locals) { + ArrayList clone = new ArrayList(); + for (LocalVariableNode node : locals) { + clone.add(new LocalVariableNode(node.name, node.desc, node.signature, labelMap.get(node.start), labelMap.get(node.end), node.index)); + } + + return clone; + } + + public static void copy(MethodNode src, MethodNode dst) { + Map labelMap = cloneLabels(src.instructions); + dst.instructions = cloneInsnList(labelMap, src.instructions); + dst.tryCatchBlocks = cloneTryCatchBlocks(labelMap, src.tryCatchBlocks); + if (src.localVariables != null) { + dst.localVariables = cloneLocals(labelMap, src.localVariables); + } + dst.visibleAnnotations = src.visibleAnnotations; + dst.invisibleAnnotations = src.invisibleAnnotations; + dst.visitMaxs(src.maxStack, src.maxLocals); + } + + public static byte[] alterMethods(String name, byte[] bytes, HashMultimap altercators) { + if (altercators.containsKey(name)) { + ClassNode cnode = createClassNode(bytes); + + for (MethodAlterator injector : altercators.get(name)) { + MethodNode method = findMethod(injector.method, cnode); + if (method == null) { + throw new RuntimeException("Method not found: " + injector.method); + } + + injector.alter(method); + } + + bytes = createBytes(cnode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + } + return bytes; + } + + public static int getLocal(List list, String name) { + int found = -1; + for (LocalVariableNode node : list) { + if (node.name.equals(name)) { + if (found >= 0) { + throw new RuntimeException("Duplicate local variable: " + name + " not coded to handle this scenario."); + } + + found = node.index; + } + } + return found; + } + + public static void replaceMethodCode(MethodNode original, MethodNode replacement) { + original.instructions.clear(); + if (original.localVariables != null) { + original.localVariables.clear(); + } + if (original.tryCatchBlocks != null) { + original.tryCatchBlocks.clear(); + } + replacement.accept(original); + } + + public static String printInsnList(InstructionComparator.InsnListSection subsection) { + InsnListPrinter p = new InsnListPrinter(); + p.visitInsnList(subsection); + return p.textString(); + } + + public static void removeBlock(InsnList insns, InstructionComparator.InsnListSection block) { + AbstractInsnNode insn = block.first; + while (true) { + AbstractInsnNode next = insn.getNext(); + insns.remove(insn); + if (insn == block.last) { + break; + } + insn = next; + } + } + + public static boolean isReturn(AbstractInsnNode node) { + switch (node.getOpcode()) { + case RET: + case RETURN: + case ARETURN: + case DRETURN: + case FRETURN: + case IRETURN: + case LRETURN: + return true; + + default: + return false; + } + } + + public static String[] getExceptionTypes(Executable exec) { + return Arrays.stream(exec.getExceptionTypes()).map(Type::getInternalName).toArray(s -> new String[s]); + } + + public static Class defineClass(ClassNode cn, int flags) { + try { + byte[] bytes = createBytes(cn, flags); + defineClass1.setAccessible(true); + Class clazz = (Class) defineClass1.invoke(Thread.currentThread().getContextClassLoader(), cn.name.replaceAll("/", "."), bytes, 0, bytes.length); + defineClass1.setAccessible(false); + return clazz; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static Class defineClass(ClassNode cn, int flags, ProtectionDomain domain) { + if (domain == null) { + return defineClass(cn, flags); + } + try { + byte[] bytes = createBytes(cn, flags); + defineClass2.setAccessible(true); + Class clazz = (Class) defineClass2.invoke(Thread.currentThread().getContextClassLoader(), cn.name.replaceAll("/", "."), bytes, 0, bytes.length, domain); + defineClass2.setAccessible(false); + return clazz; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static class CodeBlock { + public Label start = new Label(); + public Label end = new Label(); + } + + public static class ForBlock extends CodeBlock { + public Label cmp = new Label(); + public Label inc = new Label(); + public Label body = new Label(); + } + + public static abstract class MethodAlterator { + public final ObfMapping method; + + public MethodAlterator(ObfMapping method) { + this.method = method; + } + + public abstract void alter(MethodNode mv); + } + + public static abstract class MethodWriter { + public final int access; + public final ObfMapping method; + public final String[] exceptions; + + public MethodWriter(int access, ObfMapping method) { + this(access, method, null); + } + + public MethodWriter(int access, ObfMapping method, String[] exceptions) { + this.access = access; + this.method = method; + this.exceptions = exceptions; + } + + public abstract void write(MethodNode mv); + } + + public static class MethodInjector { + public final ObfMapping method; + public final InsnList needle; + public final InsnList injection; + public final boolean before; + + public MethodInjector(ObfMapping method, InsnList needle, InsnList injection, boolean before) { + this.method = method; + this.needle = needle; + this.injection = injection; + this.before = before; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/CC_ClassWriter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/CC_ClassWriter.java new file mode 100644 index 000000000..383fd30a0 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/CC_ClassWriter.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import org.objectweb.asm.ClassWriter; + +/** + * @author ChickenBones + */ +public class CC_ClassWriter extends ClassWriter { + private final boolean runtime; + + public CC_ClassWriter(int flags) { + this(flags, false); + } + + public CC_ClassWriter(int flags, boolean runtime) { + super(flags); + this.runtime = runtime; + } + + @Override + protected String getCommonSuperClass(String type1, String type2) { + String c = type1.replace('/', '.'); + String d = type2.replace('/', '.'); + if (ClassHeirachyManager.classExtends(d, c)) { + return type1; + } + if (ClassHeirachyManager.classExtends(c, d)) { + return type2; + } + do { + c = ClassHeirachyManager.getSuperClass(c, runtime); + } + while (!ClassHeirachyManager.classExtends(d, c)); + return c.replace('.', '/'); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ClassHeirachyManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ClassHeirachyManager.java new file mode 100644 index 000000000..726369343 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ClassHeirachyManager.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import net.minecraft.launchwrapper.IClassTransformer; +import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; +import nova.internal.core.Game; +import org.objectweb.asm.tree.ClassNode; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + +/** + * This is added as a class transformer if CodeChickenCore is installed. Adding it as a class + * transformer will speed evaluation up slightly by automatically caching superclasses when they are + * first loaded. + */ +public class ClassHeirachyManager implements IClassTransformer { + public static HashMap superclasses = new HashMap(); + private static LaunchClassLoader cl = (LaunchClassLoader) ClassHeirachyManager.class.getClassLoader(); + + static { + cl.addTransformerExclusion("codechicken.lib.asm"); + } + + public static String toKey(String name) { + if (ObfMapping.obfuscated) { + name = FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.', '/')).replace('/', '.'); + } + return name; + } + + public static String unKey(String name) { + if (ObfMapping.obfuscated) { + name = FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/', '.'); + } + return name; + } + + /** + * Returns true if clazz extends, either directly or indirectly, superclass. + * @param name The class in question + * @param superclass The class being extended + * @return + */ + public static boolean classExtends(String name, String superclass) { + name = toKey(name); + superclass = toKey(superclass); + + if (name.equals(superclass)) { + return true; + } + + SuperCache cache = declareClass(name); + if (cache == null)// just can't handle this + { + return false; + } + + cache.flatten(); + return cache.parents.contains(superclass); + } + + private static SuperCache declareClass(String name) { + name = toKey(name); + SuperCache cache = superclasses.get(name); + + if (cache != null) { + return cache; + } + + try { + byte[] bytes = cl.getClassBytes(unKey(name)); + if (bytes != null) { + cache = declareASM(bytes); + } + } catch (IOException e) { + Game.logger().error(e.getMessage()); + } + + if (cache != null) { + return cache; + } + + try { + cache = declareReflection(name); + } catch (ClassNotFoundException e) { + Game.logger().error(e.getMessage()); + } + + return cache; + } + + private static SuperCache declareReflection(String name) throws ClassNotFoundException { + Class aclass = Class.forName(name); + + SuperCache cache = getOrCreateCache(name); + if (aclass.isInterface()) { + cache.superclass = "java.lang.Object"; + } else if (name.equals("java.lang.Object")) { + return cache; + } else { + cache.superclass = toKey(aclass.getSuperclass().getName()); + } + + cache.add(cache.superclass); + for (Class iclass : aclass.getInterfaces()) { + cache.add(toKey(iclass.getName())); + } + + return cache; + } + + private static SuperCache declareASM(byte[] bytes) { + ClassNode node = ASMHelper.createClassNode(bytes); + String name = toKey(node.name); + + SuperCache cache = getOrCreateCache(name); + cache.superclass = toKey(node.superName.replace('/', '.')); + cache.add(cache.superclass); + for (String iclass : node.interfaces) { + cache.add(toKey(iclass.replace('/', '.'))); + } + + return cache; + } + + public static SuperCache getOrCreateCache(String name) { + SuperCache cache = superclasses.get(name); + if (cache == null) { + superclasses.put(name, cache = new SuperCache()); + } + return cache; + } + + public static String getSuperClass(String name, boolean runtime) { + name = toKey(name); + SuperCache cache = declareClass(name); + if (cache == null) { + return "java.lang.Object"; + } + + cache.flatten(); + String s = cache.superclass; + if (!runtime) { + s = FMLDeobfuscatingRemapper.INSTANCE.unmap(s); + } + return s; + } + + @Override + public byte[] transform(String name, String tname, byte[] bytes) { + if (bytes == null) { + return null; + } + + if (!superclasses.containsKey(tname)) { + declareASM(bytes); + } + + return bytes; + } + + public static class SuperCache { + public HashSet parents = new HashSet(); + String superclass; + private boolean flattened; + + public void add(String parent) { + parents.add(parent); + } + + public void flatten() { + if (flattened) { + return; + } + + for (String s : new ArrayList(parents)) { + SuperCache c = declareClass(s); + if (c != null) { + c.flatten(); + parents.addAll(c.parents); + } + } + flattened = true; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ComponentInjector.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ComponentInjector.java new file mode 100644 index 000000000..28b1ea0fa --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ComponentInjector.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import nova.core.component.Component; +import nova.core.component.ComponentProvider; +import nova.core.component.Passthrough; +import nova.core.network.NetworkTarget.Side; +import nova.core.util.ClassLoaderUtil; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * The ComponentInjector is capable of creating dynamic classes that implement a + * specified super class and implement the interfaces specified by + * {@link Component} and {@link Passthrough}. + * @param + * @author Vic Nightfall + */ +public class ComponentInjector implements Opcodes { + + private Class baseClazz; + + /** + * Cache, contains already created class objects for later use + */ + private Map>, Class> cache = new HashMap<>(); + + public ComponentInjector(Class baseClazz) { + this.baseClazz = baseClazz; + } + + public synchronized T inject(ComponentProvider provider, Class[] typeArgs, Object[] args) { + try { + List components = provider.components().stream() + .filter(component -> component.getClass().getAnnotationsByType(Passthrough.class).length > 0) + .collect(Collectors.toList()); + + if (components.size() > 0) { + List> componentClazzes = components.stream().map(c -> c.getClass()).collect(Collectors.toList()); + System.out.println(Side.get() + " " + componentClazzes); + if (cache.containsKey(componentClazzes)) + // Cached class + { + return inject(cache.get(componentClazzes).getConstructor(typeArgs).newInstance(args), provider); + } else { + Class clazz = construct(componentClazzes); + cache.put(componentClazzes, clazz); + return inject(clazz.getConstructor(typeArgs).newInstance(args), provider); + } + + } else { + // No components withPriority passthrough interfaces, we can use the + // base class. + return baseClazz.getConstructor(typeArgs).newInstance(args); + } + } catch (Exception e) { + throw new ClassLoaderUtil.ClassLoaderException("Failed to construct wrapper class for " + baseClazz, e); + } + } + + private T inject(T instance, ComponentProvider provider) throws ReflectiveOperationException { + Field f = instance.getClass().getDeclaredField("$$_provider"); + f.setAccessible(true); + f.set(instance, provider); + f.setAccessible(false); + return instance; + } + + private Class construct(List> components) { + + // Map components to specified wrapped interfaces + Map, Class> intfComponentMap = new HashMap<>(); + for (Class component : components) { + for (Passthrough pt : component.getAnnotationsByType(Passthrough.class)) { + Class intf; + try { + intf = Class.forName(pt.value()); + } catch (ClassNotFoundException exec) { + throw new ClassLoaderUtil.ClassLoaderException("Invalid passthrough \"%s\" on component %s, the specified interface doesn't exist.", pt.value(), component); + } + if (!intf.isAssignableFrom(component)) { + throw new ClassLoaderUtil.ClassLoaderException("Invalid passthrough \"%s\" on component %s, the specified interface isn't implemented.", pt.value(), component); + } + if (intfComponentMap.containsKey(intf)) { + throw new ClassLoaderUtil.ClassLoaderException("Duplicate Passthrough interface found: %s (%s, %s)", pt.value(), component, intfComponentMap.get(intf)); + } + intfComponentMap.put(intf, component); + } + } + + // Create new ClassNode from cached bytes + ClassNode clazzNode = new ClassNode(); + String name = Type.getInternalName(baseClazz); + String classname = name + "_$$_NOVA_" + cache.size(); + + // Inject block field + clazzNode.visit(V1_8, ACC_PUBLIC | ACC_SUPER, classname, null, name, intfComponentMap.keySet().stream().map(Type::getInternalName).toArray(s -> new String[s])); + clazzNode.visitField(ACC_PRIVATE | ACC_FINAL, "$$_provider", Type.getDescriptor(ComponentProvider.class), null, null).visitEnd(); + + // Add constructors + for (Constructor constructor : baseClazz.getConstructors()) { + int mod = constructor.getModifiers(); + String descr = Type.getConstructorDescriptor(constructor); + + if (Modifier.isFinal(mod) || Modifier.isPrivate(mod)) { + continue; + } + MethodVisitor mv = clazzNode.visitMethod(mod, "", descr, null, ASMHelper.getExceptionTypes(constructor)); + + // Call super constructor + mv.visitCode(); + // load this + mv.visitVarInsn(ALOAD, 0); + Class[] parameters = constructor.getParameterTypes(); + for (int i = 0; i < constructor.getParameterCount(); i++) { + // variables + mv.visitVarInsn(Type.getType(parameters[i]).getOpcode(ILOAD), i + 1); + } + mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(baseClazz), "", descr, false); + // return + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + // Add methods + for (Class intf : intfComponentMap.keySet()) { + // Create class constant + Type clazzConst = Type.getType(intf.getClass()); + + for (Method m : intf.getMethods()) { + boolean isVoid = m.getReturnType() == null; + String descr = Type.getMethodDescriptor(m); + + MethodVisitor mv = clazzNode.visitMethod(ACC_PUBLIC, m.getName(), descr, null, ASMHelper.getExceptionTypes(m)); + mv.visitCode(); + + // load block instance + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, classname, "$$_provider", Type.getDescriptor(ComponentProvider.class)); + mv.visitLdcInsn(clazzConst); + // load component instance + mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(ComponentProvider.class), "get", Type.getMethodDescriptor(Type.getType(Component.class), Type.getType(Class.class)), false); + + // add parameters + Class[] parameters = m.getParameterTypes(); + for (int i = 0; i < m.getParameterCount(); i++) { + mv.visitVarInsn(Type.getType(parameters[i]).getOpcode(ILOAD), i + 1); + } + + // invoke + mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(intf), m.getName(), descr, true); + mv.visitInsn(isVoid ? RETURN : Type.getType(m.getReturnType()).getOpcode(IRETURN)); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + } + + clazzNode.visitEnd(); + + return ASMHelper.defineClass(clazzNode, ClassWriter.COMPUTE_MAXS, baseClazz.getProtectionDomain()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/InsnListPrinter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/InsnListPrinter.java new file mode 100644 index 000000000..4a5cba910 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/InsnListPrinter.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FrameNode; +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.LookupSwitchInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MultiANewArrayInsnNode; +import org.objectweb.asm.tree.TableSwitchInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.util.Textifier; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; + +public class InsnListPrinter extends Textifier { + private boolean buildingLabelMap = false; + + public InsnListPrinter() { + super(Opcodes.ASM5); + } + + public void visitInsnList(InsnList list) { + text.clear(); + if (labelNames == null) { + labelNames = new HashMap(); + } else { + labelNames.clear(); + } + + buildingLabelMap = true; + for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) { + if (insn.getType() == 8) { + visitLabel(((LabelNode) insn).getLabel()); + } + } + + text.clear(); + buildingLabelMap = false; + + for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) { + _visitInsn(insn); + } + } + + public void visitInsnList(InstructionComparator.InsnListSection subsection) { + text.clear(); + if (labelNames == null) { + labelNames = new HashMap(); + } else { + labelNames.clear(); + } + + buildingLabelMap = true; + { + AbstractInsnNode insn = subsection.first; + while (true) { + if (insn.getType() == 8) { + visitLabel(((LabelNode) insn).getLabel()); + } + if (insn == subsection.last) { + break; + } + insn = insn.getNext(); + } + } + + text.clear(); + buildingLabelMap = false; + + { + AbstractInsnNode insn = subsection.first; + while (true) { + _visitInsn(insn); + if (insn == subsection.last) { + break; + } + insn = insn.getNext(); + } + } + } + + public void visitInsn(AbstractInsnNode insn) { + text.clear(); + if (labelNames == null) { + labelNames = new HashMap(); + } else { + labelNames.clear(); + } + + _visitInsn(insn); + } + + private void _visitInsn(AbstractInsnNode insn) { + switch (insn.getType()) { + case 0: + visitInsn(insn.getOpcode()); + break; + case 1: + IntInsnNode iinsn = (IntInsnNode) insn; + visitIntInsn(iinsn.getOpcode(), iinsn.operand); + break; + case 2: + VarInsnNode vinsn = (VarInsnNode) insn; + visitVarInsn(vinsn.getOpcode(), vinsn.var); + break; + case 3: + TypeInsnNode tinsn = (TypeInsnNode) insn; + visitTypeInsn(tinsn.getOpcode(), tinsn.desc); + break; + case 4: + FieldInsnNode finsn = (FieldInsnNode) insn; + visitFieldInsn(finsn.getOpcode(), finsn.owner, finsn.name, finsn.desc); + break; + case 5: + MethodInsnNode minsn = (MethodInsnNode) insn; + visitMethodInsn(minsn.getOpcode(), minsn.owner, minsn.name, minsn.desc); + break; + case 6: + InvokeDynamicInsnNode idinsn = (InvokeDynamicInsnNode) insn; + visitInvokeDynamicInsn(idinsn.name, idinsn.desc, idinsn.bsm, idinsn.bsmArgs); + break; + case 7: + JumpInsnNode jinsn = (JumpInsnNode) insn; + visitJumpInsn(jinsn.getOpcode(), jinsn.label.getLabel()); + break; + case 8: + LabelNode linsn = (LabelNode) insn; + visitLabel(linsn.getLabel()); + break; + case 9: + LdcInsnNode ldcinsn = (LdcInsnNode) insn; + visitLdcInsn(ldcinsn.cst); + break; + case 10: + IincInsnNode iiinsn = (IincInsnNode) insn; + visitIincInsn(iiinsn.var, iiinsn.incr); + break; + case 11: + TableSwitchInsnNode tsinsn = (TableSwitchInsnNode) insn; + Label[] tslables = new Label[tsinsn.labels.size()]; + for (int i = 0; i < tslables.length; i++) { + tslables[i] = tsinsn.labels.get(i).getLabel(); + } + visitTableSwitchInsn(tsinsn.min, tsinsn.max, tsinsn.dflt.getLabel(), tslables); + break; + case 12: + LookupSwitchInsnNode lsinsn = (LookupSwitchInsnNode) insn; + Label[] lslables = new Label[lsinsn.labels.size()]; + for (int i = 0; i < lslables.length; i++) { + lslables[i] = lsinsn.labels.get(i).getLabel(); + } + int[] lskeys = new int[lsinsn.keys.size()]; + for (int i = 0; i < lskeys.length; i++) { + lskeys[i] = lsinsn.keys.get(i); + } + visitLookupSwitchInsn(lsinsn.dflt.getLabel(), lskeys, lslables); + break; + case 13: + MultiANewArrayInsnNode ainsn = (MultiANewArrayInsnNode) insn; + visitMultiANewArrayInsn(ainsn.desc, ainsn.dims); + break; + case 14: + FrameNode fnode = (FrameNode) insn; + switch (fnode.type) { + case -1: + case 0: + visitFrame(fnode.type, fnode.local.size(), fnode.local.toArray(), fnode.stack.size(), fnode.stack.toArray()); + break; + case 1: + visitFrame(fnode.type, fnode.local.size(), fnode.local.toArray(), 0, null); + break; + case 2: + visitFrame(fnode.type, fnode.local.size(), null, 0, null); + break; + case 3: + visitFrame(fnode.type, 0, null, 0, null); + break; + case 4: + visitFrame(fnode.type, 0, null, 1, fnode.stack.toArray()); + } + break; + case 15: + LineNumberNode lnode = (LineNumberNode) insn; + visitLineNumber(lnode.line, lnode.start.getLabel()); + break; + } + } + + @Override + public void visitLabel(Label label) { + if (!buildingLabelMap && !labelNames.containsKey(label)) { + labelNames.put(label, "LEXT" + labelNames.size()); + } + super.visitLabel(label); + } + + public String textString() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + print(pw); + pw.flush(); + return sw.toString(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/InstructionComparator.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/InstructionComparator.java new file mode 100644 index 000000000..df12d50f4 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/InstructionComparator.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.LookupSwitchInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.TableSwitchInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.tree.VarInsnNode; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +import static org.objectweb.asm.tree.AbstractInsnNode.FIELD_INSN; +import static org.objectweb.asm.tree.AbstractInsnNode.IINC_INSN; +import static org.objectweb.asm.tree.AbstractInsnNode.INT_INSN; +import static org.objectweb.asm.tree.AbstractInsnNode.LDC_INSN; +import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN; +import static org.objectweb.asm.tree.AbstractInsnNode.TYPE_INSN; +import static org.objectweb.asm.tree.AbstractInsnNode.VAR_INSN; + +public class InstructionComparator { + public static boolean varInsnEqual(VarInsnNode insn1, VarInsnNode insn2) { + return insn1.var == -1 || insn2.var == -1 || insn1.var == insn2.var; + } + + public static boolean methodInsnEqual(AbstractInsnNode absnode, int Opcode, ObfMapping method) { + return absnode.getOpcode() == Opcode && absnode instanceof MethodInsnNode && method.matches((MethodInsnNode) absnode); + } + + public static boolean methodInsnEqual(MethodInsnNode insn1, MethodInsnNode insn2) { + return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc); + } + + public static boolean fieldInsnEqual(FieldInsnNode insn1, FieldInsnNode insn2) { + return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc); + } + + public static boolean ldcInsnEqual(LdcInsnNode insn1, LdcInsnNode insn2) { + return insn1.cst.equals("~") || insn2.cst.equals("~") || insn1.cst.equals(insn2.cst); + } + + public static boolean typeInsnEqual(TypeInsnNode insn1, TypeInsnNode insn2) { + return insn1.desc.equals("~") || insn2.desc.equals("~") || insn1.desc.equals(insn2.desc); + } + + public static boolean iincInsnEqual(IincInsnNode node1, IincInsnNode node2) { + return node1.var == node2.var && node1.incr == node2.incr; + } + + public static boolean intInsnEqual(IntInsnNode node1, IntInsnNode node2) { + return node1.operand == -1 || node2.operand == -1 || node1.operand == node2.operand; + } + + public static boolean insnEqual(AbstractInsnNode node1, AbstractInsnNode node2) { + if (node1.getOpcode() != node2.getOpcode()) { + return false; + } + + switch (node2.getType()) { + case VAR_INSN: + return varInsnEqual((VarInsnNode) node1, (VarInsnNode) node2); + case TYPE_INSN: + return typeInsnEqual((TypeInsnNode) node1, (TypeInsnNode) node2); + case FIELD_INSN: + return fieldInsnEqual((FieldInsnNode) node1, (FieldInsnNode) node2); + case METHOD_INSN: + return methodInsnEqual((MethodInsnNode) node1, (MethodInsnNode) node2); + case LDC_INSN: + return ldcInsnEqual((LdcInsnNode) node1, (LdcInsnNode) node2); + case IINC_INSN: + return iincInsnEqual((IincInsnNode) node1, (IincInsnNode) node2); + case INT_INSN: + return intInsnEqual((IntInsnNode) node1, (IntInsnNode) node2); + default: + return true; + } + } + + public static InsnList getImportantList(InsnList list) { + if (list.size() == 0) { + return list; + } + + HashMap labels = new HashMap(); + for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) { + if (insn instanceof LabelNode) { + labels.put((LabelNode) insn, (LabelNode) insn); + } + } + + InsnList importantNodeList = new InsnList(); + for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) { + if (insn instanceof LabelNode || insn instanceof LineNumberNode) { + continue; + } + + importantNodeList.add(insn.clone(labels)); + } + return importantNodeList; + } + + public static boolean insnListMatches(InsnList haystack, InsnList needle, int start) { + if (haystack.size() - start < needle.size()) { + return false; + } + + for (int i = 0; i < needle.size(); i++) { + if (!insnEqual(haystack.get(i + start), needle.get(i))) { + return false; + } + } + return true; + } + + public static List insnListFind(InsnList haystack, InsnList needle) { + LinkedList list = new LinkedList(); + for (int start = 0; start <= haystack.size() - needle.size(); start++) { + if (insnListMatches(haystack, needle, start)) { + list.add(start); + } + } + + return list; + } + + public static List insnListFindStart(InsnList haystack, InsnList needle) { + LinkedList callNodes = new LinkedList(); + for (int callPoint : insnListFind(haystack, needle)) { + callNodes.add(haystack.get(callPoint)); + } + return callNodes; + } + + public static List insnListFindEnd(InsnList haystack, InsnList needle) { + LinkedList callNodes = new LinkedList(); + for (int callPoint : insnListFind(haystack, needle)) { + callNodes.add(haystack.get(callPoint + needle.size() - 1)); + } + return callNodes; + } + + public static List insnListFindL(InsnList haystack, InsnList needle) { + HashSet controlFlowLabels = new HashSet(); + + for (AbstractInsnNode insn = haystack.getFirst(); insn != null; insn = insn.getNext()) { + switch (insn.getType()) { + case 8: + case 15: + break; + case 7: + JumpInsnNode jinsn = (JumpInsnNode) insn; + controlFlowLabels.add(jinsn.label); + break; + case 11: + TableSwitchInsnNode tsinsn = (TableSwitchInsnNode) insn; + for (LabelNode label : tsinsn.labels) { + controlFlowLabels.add(label); + } + break; + case 12: + LookupSwitchInsnNode lsinsn = (LookupSwitchInsnNode) insn; + for (LabelNode label : lsinsn.labels) { + controlFlowLabels.add(label); + } + break; + } + } + + LinkedList list = new LinkedList(); + nextsection: + for (int start = 0; start <= haystack.size() - needle.size(); start++) { + InsnListSection section = insnListMatchesL(haystack, needle, start, controlFlowLabels); + if (section != null) { + for (InsnListSection asection : list) { + if (asection.last == section.last) { + continue nextsection; + } + } + + list.add(section); + } + } + + return list; + } + + private static InsnListSection insnListMatchesL(InsnList haystack, InsnList needle, int start, HashSet controlFlowLabels) { + int h = start, n = 0; + for (; h < haystack.size() && n < needle.size(); h++) { + AbstractInsnNode insn = haystack.get(h); + if (insn.getType() == 15) { + continue; + } + if (insn.getType() == 8 && !controlFlowLabels.contains(insn)) { + continue; + } + + if (!insnEqual(haystack.get(h), needle.get(n))) { + return null; + } + n++; + } + if (n != needle.size()) { + return null; + } + + return new InsnListSection(haystack, start, h - 1); + } + + public static class InsnListSection { + public AbstractInsnNode first; + public AbstractInsnNode last; + + public InsnListSection(AbstractInsnNode first, AbstractInsnNode last) { + this.first = first; + this.last = last; + } + + public InsnListSection(InsnList haystack, int start, int end) { + this(haystack.get(start), haystack.get(end)); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ObfMapping.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ObfMapping.java new file mode 100644 index 000000000..95776e95d --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/ObfMapping.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import com.google.common.base.Objects; +import net.minecraft.launchwrapper.LaunchClassLoader; +import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; +import nova.internal.core.Game; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.commons.Remapper; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; + +import java.io.IOException; + +/** + * @author ChickenBones + */ +public class ObfMapping { + public static final boolean obfuscated; + /** + * CCC will deal withPriority this. + */ + public static Remapper runtimeMapper = FMLDeobfuscatingRemapper.INSTANCE; + public static Remapper mcpMapper = null; + + static { + boolean obf = true; + try { + obf = ((LaunchClassLoader) ObfMapping.class.getClassLoader()).getClassBytes("net.minecraft.world.World") == null; + } catch (IOException iox) { + Game.logger().error(iox.getMessage()); + } + obfuscated = obf; + } + + public String s_owner; + public String s_name; + public String s_desc; + + public boolean runtime; + + public ObfMapping(String owner) { + this(owner, "", ""); + } + + public ObfMapping(String owner, String name, String desc) { + this.s_owner = owner; + this.s_name = name; + this.s_desc = desc; + + if (s_owner.contains(".")) { + throw new IllegalArgumentException(s_owner); + } + + if (mcpMapper != null) { + map(mcpMapper); + } + } + + public ObfMapping(ObfMapping descmap, String subclass) { + this(subclass, descmap.s_name, descmap.s_desc); + } + + public static ObfMapping fromDesc(String s) { + int lastDot = s.lastIndexOf('.'); + if (lastDot < 0) { + return new ObfMapping(s, "", ""); + } + int sep = s.indexOf('(');// methods + int sep_end = sep; + if (sep < 0) { + sep = s.indexOf(' ');// some stuffs + sep_end = sep + 1; + } + if (sep < 0) { + sep = s.indexOf(':');// fields + sep_end = sep + 1; + } + if (sep < 0) { + return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot + 1), ""); + } + + return new ObfMapping(s.substring(0, lastDot), s.substring(lastDot + 1, sep), s.substring(sep_end)); + } + + public ObfMapping subclass(String subclass) { + return new ObfMapping(this, subclass); + } + + public boolean matches(MethodNode node) { + return s_name.equals(node.name) && s_desc.equals(node.desc); + } + + public boolean matches(MethodInsnNode node) { + return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc); + } + + public AbstractInsnNode toInsn(int opcode) { + if (isClass()) { + return new TypeInsnNode(opcode, s_owner); + } else if (isMethod()) { + return new MethodInsnNode(opcode, s_owner, s_name, s_desc); + } else { + return new FieldInsnNode(opcode, s_owner, s_name, s_desc); + } + } + + public void visitTypeInsn(MethodVisitor mv, int opcode) { + mv.visitTypeInsn(opcode, s_owner); + } + + public void visitMethodInsn(MethodVisitor mv, int opcode) { + mv.visitMethodInsn(opcode, s_owner, s_name, s_desc); + } + + public void visitFieldInsn(MethodVisitor mv, int opcode) { + mv.visitFieldInsn(opcode, s_owner, s_name, s_desc); + } + + public boolean isClass(String name) { + return name.replace('.', '/').equals(s_owner); + } + + public boolean matches(String name, String desc) { + return s_name.equals(name) && s_desc.equals(desc); + } + + public boolean matches(FieldNode node) { + return s_name.equals(node.name) && s_desc.equals(node.desc); + } + + public boolean matches(FieldInsnNode node) { + return s_owner.equals(node.owner) && s_name.equals(node.name) && s_desc.equals(node.desc); + } + + public String javaClass() { + return s_owner.replace('/', '.'); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ObfMapping)) { + return false; + } + + ObfMapping desc = (ObfMapping) obj; + return s_owner.equals(desc.s_owner) && s_name.equals(desc.s_name) && s_desc.equals(desc.s_desc); + } + + @Override + public int hashCode() { + return Objects.hashCode(s_desc, s_name, s_owner); + } + + @Override + public String toString() { + if (s_name.length() == 0) { + return "[" + s_owner + "]"; + } + if (s_desc.length() == 0) { + return "[" + s_owner + "." + s_name + "]"; + } + return "[" + (isMethod() ? methodDesc() : fieldDesc()) + "]"; + } + + public String methodDesc() { + return s_owner + "." + s_name + s_desc; + } + + public String fieldDesc() { + return s_owner + "." + s_name + ":" + s_desc; + } + + public boolean isClass() { + return s_name.length() == 0; + } + + public boolean isMethod() { + return s_desc.contains("("); + } + + public boolean isField() { + return !isClass() && !isMethod(); + } + + public ObfMapping map(Remapper mapper) { + if (isMethod()) { + s_name = mapper.mapMethodName(s_owner, s_name, s_desc); + } else if (isField()) { + s_name = mapper.mapFieldName(s_owner, s_name, s_desc); + } + + s_owner = mapper.mapType(s_owner); + + if (isMethod()) { + s_desc = mapper.mapMethodDesc(s_desc); + } else if (s_desc.length() > 0) { + s_desc = mapper.mapDesc(s_desc); + } + + return this; + } + + public ObfMapping toRuntime() { + if (!runtime) { + map(runtimeMapper); + } + + runtime = true; + return this; + } + + public ObfMapping copy() { + return new ObfMapping(s_owner, s_name, s_desc); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/TemplateInjector.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/TemplateInjector.java new file mode 100644 index 000000000..52f7fff99 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/TemplateInjector.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; + +import com.google.common.collect.HashBiMap; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * The template injection manager is capable of injecting default interfaces into classes. + * The default interface will have no overrides, thereby implementing the default methods. + * @author Calclavia, ChickenBones + */ +public class TemplateInjector { + + public static final TemplateInjector instance = new TemplateInjector(); + private HashBiMap templates = HashBiMap.create(); + + /** + * Registers a class to be injected by a default interface + * @param className - Class that will be injected + * @param template - Default interface used as a template to inject in the templateName + */ + public void registerTemplate(String className, Class template) { + templates.put(className, new InjectionTemplate(template.getName())); + } + + private ClassNode getClassNode(String name) { + try { + return ASMHelper.createClassNode(ASMHelper.cl.getClassBytes(name.replace('/', '.'))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public class InjectionTemplate { + /** + * The default interface class name that acts as a template. + */ + public final String templateName; + + /** + * The methods to be injected upon inject(ClassNode cnode); + */ + public ArrayList methodImplementations = new ArrayList<>(); + + public InjectionTemplate(String templateName) { + this.templateName = templateName; + + /** + * Read the class node, scanning all the method implementations + */ + ClassNode cnode = getClassNode(templateName); + + for (MethodNode method : cnode.methods) { + methodImplementations.add(method); + method.desc = new ObfMapping(cnode.name, method.name, method.desc).toRuntime().s_desc; + } + } + + /** + * Patches the cnode withPriority the methods from this template. + * @param cnode + * @return + */ + public boolean inject(ClassNode cnode) { + + /** + * Inject the interface + */ + String interfaceByteName = templateName.replace(".", "/"); + + if (!cnode.interfaces.contains(interfaceByteName)) { + cnode.interfaces.add(interfaceByteName); + } + + boolean changed = false; + + List names = new LinkedList<>(); + + for (MethodNode method : cnode.methods) { + ObfMapping m = new ObfMapping(cnode.name, method.name, method.desc).toRuntime(); + names.add(m.s_name + m.s_desc); + } + + for (MethodNode impl : this.methodImplementations) { + //Ignore the constructor + if (!impl.name.equals("")) { + + //If the method is ALREADY implemented, then skip it. + if (names.contains(impl.name + impl.desc)) { + continue; + } + + ObfMapping mapping = new ObfMapping(cnode.name, impl.name, impl.desc).toRuntime(); + MethodNode copy = new MethodNode(impl.access, mapping.s_name, mapping.s_desc, impl.signature, + impl.exceptions == null ? null : impl.exceptions.toArray(new String[impl.exceptions.size()])); + ASMHelper.copy(impl, copy); + cnode.methods.add(impl); + changed = true; + } + } + + return changed; + } + } + +} \ No newline at end of file diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/package-info.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/package-info.java new file mode 100644 index 000000000..136f2221c --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/lib/package-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +/** + * ASM classes are used to help withPriority class transformations and bytecode injection. + * The ASM library is based on ChickenBone's ASM library. + * @author Calclavia + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.lib; \ No newline at end of file diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/ChunkTransformer.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/ChunkTransformer.java new file mode 100644 index 000000000..e7ed4dda9 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/ChunkTransformer.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.transformers; + +import nova.core.wrapper.mc.forge.v1_11.asm.lib.ASMHelper; +import nova.core.wrapper.mc.forge.v1_11.asm.lib.ObfMapping; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class ChunkTransformer implements Transformer { + + @Override + public void transform(ClassNode cnode) { + System.out.println("[NOVA] Transforming Chunk class for chunkModified event."); + + //obf name: func_177436_a + MethodNode method = ASMHelper.findMethod(new ObfMapping("net/minecraft/world/chunk/Chunk", "setBlockState", "(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/block/state/IBlockState;"), cnode); + + System.out.println("[NOVA] Found method " + method.name); + + InsnList list = new InsnList(); + list.add(new VarInsnNode(ALOAD, 0)); //this + list.add(new VarInsnNode(ALOAD, 1)); //BlockPos + list.add(new VarInsnNode(ALOAD, 8)); //oldBlock IBlockState + list.add(new VarInsnNode(ALOAD, 2)); //newBlock IBlockState + list.add(new MethodInsnNode(INVOKESTATIC, "nova/core/wrapper/mc/forge/v1_11/asm/StaticForwarder", "chunkSetBlockEvent", "(Lnet/minecraft/world/chunk/Chunk;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;Lnet/minecraft/block/state/IBlockState;)V", false)); + + AbstractInsnNode lastInsn = method.instructions.getLast(); + while (lastInsn instanceof LabelNode || lastInsn instanceof LineNumberNode) { + lastInsn = lastInsn.getPrevious(); + } + + if (ASMHelper.isReturn(lastInsn)) { + method.instructions.insertBefore(lastInsn, list); + } else { + method.instructions.insert(list); + } + + System.out.println("[NOVA] Injected instruction to method: " + method.name); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/TileEntityTransformer.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/TileEntityTransformer.java new file mode 100644 index 000000000..db682a886 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/TileEntityTransformer.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.transformers; + +import nova.core.wrapper.mc.forge.v1_11.asm.lib.ASMHelper; +import nova.core.wrapper.mc.forge.v1_11.asm.lib.InstructionComparator; +import nova.core.wrapper.mc.forge.v1_11.asm.lib.ObfMapping; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class TileEntityTransformer implements Transformer { + + @Override + public void transform(ClassNode cnode) { + + System.out.println("[NOVA] Transforming TileEntity class for dynamic instance injection."); + + ObfMapping obfMap = new ObfMapping("aqk", "a", "(Laid;Ldr;)Laqk;"); + ObfMapping deobfMap = new ObfMapping("net/minecraft/tileentity/TileEntity", "create", "(Lnet/minecraft/world/World;Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/tileentity/TileEntity;"); + + MethodNode method = ASMHelper.findMethod(obfMap, cnode); + + if (method == null) { + System.out.println("[NOVA] Lookup " + obfMap + " failed. You are probably in a deobf environment."); + method = ASMHelper.findMethod(deobfMap, cnode); + + if (method == null) { + System.out.println("[NOVA] Lookup " + deobfMap + " failed!"); + } + } + + System.out.println("[NOVA] Transforming method " + method.name); + + ASMHelper.removeBlock(method.instructions, new InstructionComparator.InsnListSection(method.instructions, 31, 44)); + + InsnList list = new InsnList(); + list.add(new VarInsnNode(ALOAD, 0)); // World + list.add(new VarInsnNode(ALOAD, 1)); // NBTTagCompound + list.add(new VarInsnNode(ALOAD, 4)); // Class + list.add(new MethodInsnNode(INVOKESTATIC, "nova/core/wrapper/mc/forge/v1_11/asm/StaticForwarder", "loadTileEntityHook", "(Lnet/minecraft/world/World;Lnet/minecraft/nbt/NBTTagCompound;Ljava/lang/Class;)Lnet/minecraft/tileentity/TileEntity;", false)); + list.add(new VarInsnNode(ASTORE, 2)); // TileEntity + + method.instructions.insert(method.instructions.get(31), list); + + System.out.println("[NOVA] Injected instruction to method: " + method.name); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/Transformer.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/Transformer.java new file mode 100644 index 000000000..33fb0a284 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/Transformer.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.transformers; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; + +public interface Transformer extends Opcodes { + + public void transform(ClassNode cnode); +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/Transformers.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/Transformers.java new file mode 100644 index 000000000..6876bfc38 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/asm/transformers/Transformers.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.asm.transformers; + +import net.minecraft.launchwrapper.IClassTransformer; +import nova.core.wrapper.mc.forge.v1_11.asm.lib.ASMHelper; +import org.objectweb.asm.tree.ClassNode; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public final class Transformers implements IClassTransformer { + + private static Map> transformers = new HashMap<>(); + + public Transformers() { + registerTransformer(new ChunkTransformer(), "net.minecraft.world.chunk.Chunk"); + //registerTransformer(new TileEntityTransformer(), "net.minecraft.tileentity.TileEntity"); + } + + public static void registerTransformer(Transformer transformer, String... classes) { + Objects.requireNonNull(classes); + for (String clazz : classes) { + List list = transformers.getOrDefault(clazz, new ArrayList<>()); + list.add(transformer); + transformers.put(clazz, list); + } + } + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (transformers.containsKey(transformedName)) { + ClassNode cnode = ASMHelper.createClassNode(basicClass); + transformers.get(transformedName).forEach(t -> t.transform(cnode)); + return ASMHelper.createBytes(cnode, 0); + } + return basicClass; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/ClientModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/ClientModule.java new file mode 100644 index 000000000..b87359207 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/ClientModule.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.game.ClientManager; +import nova.core.wrapper.mc.forge.v1_11.manager.FWClientManager; +import se.jbee.inject.bind.BinderModule; + +public class ClientModule extends BinderModule { + + @Override + protected void declare() { + bind(ClientManager.class).to(FWClientManager.class); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/ComponentModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/ComponentModule.java new file mode 100644 index 000000000..ac50e1676 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/ComponentModule.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.entity.component.RigidBody; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.BWRigidBody; +import se.jbee.inject.bind.BinderModule; + +/** + * @author Calclavia + */ +public class ComponentModule extends BinderModule { + + @Override + protected void declare() { + bind(RigidBody.class).to(BWRigidBody.class); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/GameInfoModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/GameInfoModule.java new file mode 100644 index 000000000..b6790d0b1 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/GameInfoModule.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.game.GameInfo; +import se.jbee.inject.Dependency; +import se.jbee.inject.Injector; +import se.jbee.inject.Supplier; +import se.jbee.inject.bind.BinderModule; + +public class GameInfoModule extends BinderModule { + private static final GameInfo minecraft = new GameInfo("minecraft", "1.11"); + + @Override + protected void declare() { + bind(GameInfo.class).toSupplier(GameInfoSupplier.class); + } + + public static class GameInfoSupplier implements Supplier { + @Override + public GameInfo supply(Dependency dependency, Injector injector) { + return minecraft; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/KeyModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/KeyModule.java new file mode 100644 index 000000000..70fab59d6 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/KeyModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.game.InputManager; +import nova.core.wrapper.mc.forge.v1_11.util.MCInputManager; +import se.jbee.inject.bind.BinderModule; + +public class KeyModule extends BinderModule { + + @Override + protected void declare() { + bind(InputManager.class).to(MCInputManager.class); + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/LanguageModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/LanguageModule.java new file mode 100644 index 000000000..af3f7a24a --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/LanguageModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.util.registry.LanguageManager; +import nova.core.wrapper.mc.forge.v1_11.util.MCLanguageManager; +import se.jbee.inject.bind.BinderModule; + +public class LanguageModule extends BinderModule { + + @Override + protected void declare() { + bind(LanguageManager.class).to(MCLanguageManager.class); + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/NetworkModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/NetworkModule.java new file mode 100644 index 000000000..1682d0905 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/NetworkModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.network.NetworkManager; +import nova.core.wrapper.mc.forge.v1_11.network.netty.MCNetworkManager; +import se.jbee.inject.bind.BinderModule; + +public class NetworkModule extends BinderModule { + + @Override + protected void declare() { + bind(NetworkManager.class).to(MCNetworkManager.class); + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/RenderModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/RenderModule.java new file mode 100644 index 000000000..1aec0cd07 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/RenderModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.render.RenderManager; +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward.BWClientRenderManager; +import se.jbee.inject.bind.BinderModule; + +public class RenderModule extends BinderModule { + + @Override + protected void declare() { + bind(RenderManager.class).to(BWClientRenderManager.class); + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/SaveModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/SaveModule.java new file mode 100644 index 000000000..339d28ede --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/SaveModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.core.util.registry.RetentionManager; +import nova.core.wrapper.mc.forge.v1_11.manager.MCRetentionManager; +import se.jbee.inject.bind.BinderModule; + +public class SaveModule extends BinderModule { + + @Override + protected void declare() { + bind(RetentionManager.class).to(MCRetentionManager.class); + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/TickerModule.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/TickerModule.java new file mode 100644 index 000000000..54be1bf1a --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/depmodules/TickerModule.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.depmodules; + +import nova.internal.core.tick.UpdateTicker; +import se.jbee.inject.Dependency; +import se.jbee.inject.Injector; +import se.jbee.inject.Supplier; +import se.jbee.inject.bind.BinderModule; +import se.jbee.inject.util.Scoped; + +/** + * @author Calclavia + */ +public class TickerModule extends BinderModule { + public static final UpdateTicker.SynchronizedTicker synchronizedTicker = new UpdateTicker.SynchronizedTicker(); + public static final UpdateTicker.ThreadTicker threadTicker = new UpdateTicker.ThreadTicker(); + public static UpdateTicker.TickingThread tickingThread; + + public TickerModule() { + super(Scoped.DEPENDENCY_TYPE); + } + + @Override + protected void declare() { + bind(UpdateTicker.SynchronizedTicker.class).toSupplier(SynchronizedTickerSupplier.class); + bind(UpdateTicker.ThreadTicker.class).toSupplier(ThreadTickerSupplier.class); + + /** + * Initiated threaded ticker + */ + tickingThread = new UpdateTicker.TickingThread(threadTicker, 20); + tickingThread.start(); + } + + public static class SynchronizedTickerSupplier implements Supplier { + @Override + public UpdateTicker.SynchronizedTicker supply(Dependency dependency, Injector injector) { + return synchronizedTicker; + } + } + + public static class ThreadTickerSupplier implements Supplier { + @Override + public UpdateTicker.ThreadTicker supply(Dependency dependency, Injector injector) { + return threadTicker; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/ClientProxy.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/ClientProxy.java new file mode 100644 index 000000000..259cfcabd --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/ClientProxy.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.launcher; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraftforge.client.model.ModelLoader; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.client.FMLClientHandler; +import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.client.registry.RenderingRegistry; +import nova.core.entity.Entity; +import nova.core.entity.EntityFactory; +import nova.core.wrapper.mc.forge.v1_11.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWTileRenderer; +import nova.core.wrapper.mc.forge.v1_11.wrapper.particle.backward.BWParticle; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.particle.forward.FWParticle; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.FWEntityRenderer; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward.FWItem; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * @author Calclavia + */ +public class ClientProxy extends CommonProxy { + @Override + public void preInit() { + super.preInit(); + MinecraftForge.EVENT_BUS.register(RenderUtility.instance); + ClientRegistry.bindTileEntitySpecialRenderer(FWTile.class, FWTileRenderer.instance); + RenderUtility.instance.preInit(); + } + + @Override + public void init() { + super.init(); + RenderingRegistry.registerEntityRenderingHandler(FWEntity.class, FWEntityRenderer.instance); + } + + @Override + public void registerItem(FWItem item) { + super.registerItem(item); + + //Hacks to inject custom item definition + ModelLoader.setCustomMeshDefinition(item, stack -> new ModelResourceLocation(Item.REGISTRY.getNameForObject(item), "inventory")); + } + + @Override + public void postRegisterBlock(FWBlock block) { + super.postRegisterBlock(block); + + //Hack to inject custom itemblock definition + Item itemFromBlock = Item.getItemFromBlock(block); + + ModelLoader.setCustomMeshDefinition(itemFromBlock, stack -> new ModelResourceLocation(Item.REGISTRY.getNameForObject(itemFromBlock), "inventory")); + } + + @Override + public boolean isPaused() { + if (FMLClientHandler.instance().getClient().isSingleplayer() && !FMLClientHandler.instance().getClient().getIntegratedServer().getPublic()) { + GuiScreen screen = FMLClientHandler.instance().getClient().currentScreen; + if (screen != null) { + if (screen.doesGuiPauseGame()) { + return true; + } + } + } + return false; + } + + @Override + public Entity spawnParticle(net.minecraft.world.World world, EntityFactory factory) { + //Backward entity particle unwrapper + Entity build = factory.build(); + if (build instanceof BWParticle) { + Particle particle = ((BWParticle) build).createParticle(world); + FMLClientHandler.instance().getClient().effectRenderer.addEffect(particle); + return Game.natives().toNova(particle); + } else { + FWParticle bwEntityFX = new FWParticle(world, factory); + FMLClientHandler.instance().getClient().effectRenderer.addEffect(bwEntityFX); + return bwEntityFX.wrapped; + } + } + + @Override + public Entity spawnParticle(net.minecraft.world.World world, Entity entity) { + //Backward entity particle unwrapper + if (entity instanceof BWParticle) { + Particle particle = ((BWParticle) entity).createParticle(world); + Vector3D position = entity.position(); + particle.posX = position.getX(); + particle.posY = position.getY(); + particle.posZ = position.getZ(); + FMLClientHandler.instance().getClient().effectRenderer.addEffect(particle); + return Game.natives().toNova(particle); + } else { + FWParticle bwEntityFX = new FWParticle(world, entity); + FMLClientHandler.instance().getClient().effectRenderer.addEffect(bwEntityFX); + return bwEntityFX.wrapped; + } + } + + @Override + public EntityPlayer getClientPlayer() { + return Minecraft.getMinecraft().player; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/CommonProxy.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/CommonProxy.java new file mode 100644 index 000000000..ffd9fe85d --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/CommonProxy.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.launcher; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.fml.common.registry.EntityRegistry; +import net.minecraftforge.fml.common.registry.GameRegistry; +import nova.core.entity.Entity; +import nova.core.entity.EntityFactory; +import nova.core.loader.Loadable; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWTileUpdater; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward.FWItem; + +import java.util.Set; + +import net.minecraft.util.ResourceLocation; + +/** + * @author Calclavia + */ +public class CommonProxy implements Loadable { + @Override + public void preInit() { + GameRegistry.registerTileEntity(FWTile.class, "nova:novaTile"); + GameRegistry.registerTileEntity(FWTileUpdater.class, "nova:novaTileUpdater"); + EntityRegistry.registerModEntity(new ResourceLocation("nova", "novaEntity"), FWEntity.class, "novaEntity", 1, NovaMinecraft.instance, 64, 20, true); + } + + public void registerResourcePacks(Set> modClasses) { + + } + + public void registerItem(FWItem item) { + + } + + public void postRegisterBlock(FWBlock block) { + + } + + public Entity spawnParticle(net.minecraft.world.World world, EntityFactory factory) { + return null; + } + + public Entity spawnParticle(net.minecraft.world.World world, Entity entity) { + return null; + } + + public boolean isPaused() { + return false; + } + + public EntityPlayer getClientPlayer() { + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/FMLEventHandler.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/FMLEventHandler.java new file mode 100644 index 000000000..1089c4c0e --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/FMLEventHandler.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.launcher; + +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import nova.core.event.PlayerEvent; +import nova.internal.core.Game; + +/** + * Handles FML events and forwards them to NOVA. + * @author Calclavia + */ +public class FMLEventHandler { + @SubscribeEvent + public void playerJoin(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent evt) { + Game.events().publish(new PlayerEvent.Join(Game.natives().toNova(evt.player))); + } + + @SubscribeEvent + public void playerLeave(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent evt) { + Game.events().publish(new PlayerEvent.Leave(Game.natives().toNova(evt.player))); + } + + @SubscribeEvent + public void tickEnd(TickEvent.ServerTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + Game.syncTicker().update(); + } + } + + @SubscribeEvent + public void tickEnd(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + Game.syncTicker().update(); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/FMLProgressBar.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/FMLProgressBar.java new file mode 100644 index 000000000..3f350a87a --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/FMLProgressBar.java @@ -0,0 +1,34 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package nova.core.wrapper.mc.forge.v1_11.launcher; + +import net.minecraftforge.fml.common.ProgressManager.ProgressBar; + +/** + * Wrapper class for FML progress bar that is shown when Minecraft boots. + * + * @author ExE Boss + */ +public class FMLProgressBar extends nova.core.util.AbstractProgressBar { + + private final ProgressBar progressBar; + + public FMLProgressBar(ProgressBar progressBar) { + this.progressBar = progressBar; + } + + @Override + public void stepImpl(String s) { + if (this.progressBar.getStep() >= this.progressBar.getSteps()) return; + this.progressBar.step(s); + } + + @Override + protected void finishImpl() { + while (progressBar.getStep() < progressBar.getSteps()) + progressBar.step(""); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/ForgeEventHandler.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/ForgeEventHandler.java new file mode 100644 index 000000000..54e808c09 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/ForgeEventHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.launcher; + +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock; +import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.oredict.OreDictionary; +import nova.core.item.Item; +import nova.core.item.ItemDictionary; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.ItemConverter; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * @author Stan, Calclavia + */ +public class ForgeEventHandler { + + @SubscribeEvent + public void worldUnload(WorldEvent.Load evt) { + Game.events().publish(new nova.core.event.WorldEvent.Load(Game.natives().toNova(evt.getWorld()))); + } + + @SubscribeEvent + public void worldLoad(WorldEvent.Unload evt) { + Game.events().publish(new nova.core.event.WorldEvent.Unload(Game.natives().toNova(evt.getWorld()))); + } + + @SubscribeEvent + public void onOreRegister(OreDictionary.OreRegisterEvent event) { + ItemDictionary novaItemDictionary = Game.itemDictionary(); + + Item item = ItemConverter.instance().getNovaItem(event.getOre()); + if (!novaItemDictionary.get(event.getName()).contains(item)) { + novaItemDictionary.add(event.getName(), item); + } + } + + @SubscribeEvent + public void playerInteractEvent(PlayerInteractEvent event) { + if (event.getWorld() != null && event.getPos() != null) { + nova.core.event.PlayerEvent.Interact evt = new nova.core.event.PlayerEvent.Interact( + Game.natives().toNova(event.getWorld()), + new Vector3D(event.getPos().getX(), event.getPos().getY(), event.getPos().getZ()), + Game.natives().toNova(event.getEntityPlayer()), + nova.core.event.PlayerEvent.Interact.Action.values()[toNovaInteractOrdinal(event)] + ); + + Game.events().publish(evt); + + if (event instanceof RightClickBlock) { + ((RightClickBlock)event).setUseBlock(Event.Result.values()[evt.useBlock.ordinal()]); + ((RightClickBlock)event).setUseItem(Event.Result.values()[evt.useItem.ordinal()]); + } else if (event instanceof LeftClickBlock) { + ((LeftClickBlock)event).setUseBlock(Event.Result.values()[evt.useBlock.ordinal()]); + ((LeftClickBlock)event).setUseItem(Event.Result.values()[evt.useItem.ordinal()]); + } + if (event.isCancelable()) event.setCanceled(evt.isCanceled()); + } + } + + private static int toNovaInteractOrdinal(PlayerInteractEvent event) { + if (event instanceof RightClickBlock) return 1; + else if (event instanceof LeftClickBlock) return 2; + else return 0; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/NovaMinecraft.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/NovaMinecraft.java new file mode 100644 index 000000000..958fc60a7 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/launcher/NovaMinecraft.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.launcher; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.Metadata; +import net.minecraftforge.fml.common.ModMetadata; +import net.minecraftforge.fml.common.ProgressManager; +import net.minecraftforge.fml.common.ProgressManager.ProgressBar; +import net.minecraftforge.fml.common.SidedProxy; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.event.FMLServerStartingEvent; +import net.minecraftforge.fml.common.event.FMLServerStoppingEvent; +import net.minecraftforge.fml.relauncher.FMLInjectionData; +import nova.core.deps.MavenDependency; +import nova.core.event.ServerEvent; +import nova.core.loader.Loadable; +import nova.core.wrapper.mc.forge.v1_11.NovaMinecraftPreloader; +import nova.core.wrapper.mc.forge.v1_11.depmodules.ClientModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.ComponentModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.GameInfoModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.KeyModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.LanguageModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.NetworkModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.RenderModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.SaveModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.TickerModule; +import nova.core.wrapper.mc.forge.v1_11.recipes.MinecraftRecipeRegistry; +import nova.core.wrapper.mc.forge.v1_11.wrapper.DirectionConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.BlockConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.world.WorldConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.cuboid.CuboidConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.data.DataWrapper; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.EntityConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.inventory.InventoryConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.OreDictionaryIntegration; +import nova.internal.core.Game; +import nova.internal.core.bootstrap.DependencyInjectionEntryPoint; +import nova.internal.core.deps.DepDownloader; +import nova.internal.core.launch.InitializationException; +import nova.internal.core.launch.NovaLauncher; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * The main Nova Minecraft Wrapper loader, using Minecraft Forge. + * @author Calclavia + */ +@Mod(modid = NovaMinecraft.id, name = NovaMinecraft.name, version = NovaMinecraftPreloader.version, acceptableRemoteVersions = "*") +public class NovaMinecraft { + + public static final String id = "nova"; + public static final String name = "NOVA"; + public static final String mcId = "minecraft"; + + @SidedProxy(clientSide = "nova.core.wrapper.mc.forge.v1_11.launcher.ClientProxy", serverSide = "nova.core.wrapper.mc.forge.v1_11.launcher.CommonProxy") + public static CommonProxy proxy; + @Mod.Instance(id) + public static NovaMinecraft instance; + private static NovaLauncher launcher; + @Metadata(id) + private static ModMetadata modMetadata; + + private static Set nativeConverters; + + /** + * ORDER OF LOADING. + * + * 1. Native Loaders 2. Native Converters 3. Mods + */ + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent evt) { + try { + /** + * Search through all classes withPriority @NovaMod + */ + DependencyInjectionEntryPoint diep = new DependencyInjectionEntryPoint(); + diep.install(NetworkModule.class); + diep.install(SaveModule.class); + diep.install(TickerModule.class); + diep.install(LanguageModule.class); + diep.install(KeyModule.class); + diep.install(ClientModule.class); + diep.install(GameInfoModule.class); + diep.install(RenderModule.class); + diep.install(ComponentModule.class); + + Set> modClasses = NovaMinecraftPreloader.modClasses; + + proxy.registerResourcePacks(modClasses); + launcher = new NovaLauncher(diep, modClasses); + + Game.inject(diep); + + /** + * Register native converters + */ + Game.natives().registerConverter(new DataWrapper()); + Game.natives().registerConverter(new EntityConverter()); + Game.natives().registerConverter(new BlockConverter()); + Game.natives().registerConverter(new ItemConverter()); + Game.natives().registerConverter(new WorldConverter()); + Game.natives().registerConverter(new CuboidConverter()); + Game.natives().registerConverter(new InventoryConverter()); + Game.natives().registerConverter(new VectorConverter()); + Game.natives().registerConverter(new DirectionConverter()); + + /** + * Initiate recipe and ore dictionary integration + */ + OreDictionaryIntegration.instance.registerOreDictionary(); + MinecraftRecipeRegistry.instance.registerRecipes(); + + /** + * Download dependencies + */ + launcher.generateDependencies(); + + try { + for (List dependencies : launcher.getNeededDeps().values()) { + for (MavenDependency dep : dependencies) { + DepDownloader.downloadDepdency(dep.getDownloadURL(), FMLInjectionData.data()[6] + "/mods/" + dep.getPath()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + ProgressBar progressBar = ProgressManager.push("Loading NOVA mods", modClasses.size(), true); + launcher.load(new FMLProgressBar(progressBar)); + ProgressManager.pop(progressBar); + + /** + * Instantiate native loaders + */ + nativeConverters = Game.natives().getNativeConverters().stream().filter(n -> n instanceof Loadable).map(n -> (Loadable) n).collect(Collectors.toSet()); + nativeConverters.stream().forEachOrdered(Loadable::preInit); + + Game.blocks().init(); + Game.items().init(); + Game.entities().init(); + Game.render().init(); + Game.language().init(); + + //Load preInit + progressBar = ProgressManager.push("Pre-initializing NOVA mods", modClasses.size(), true); + launcher.preInit(new FMLProgressBar(progressBar)); + while (progressBar.getStep() < progressBar.getSteps()) + progressBar.step("null"); + ProgressManager.pop(progressBar); + + // Initiate config system TODO: Storables + // launcher.getLoadedModMap().forEach((mod, loader) -> { + // Configuration config = new Configuration(new File(evt.getModConfigurationDirectory(), mod.name())); + // ConfigManager.instance.sync(config, loader.getClass().getPackage().getName()); + // }); + + proxy.preInit(); + + /** + * Register event handlers + */ + MinecraftForge.EVENT_BUS.register(new ForgeEventHandler()); + FMLCommonHandler.instance().bus().register(new FMLEventHandler()); + MinecraftForge.EVENT_BUS.register(Game.retention()); + } catch (Exception e) { + System.out.println("Error during preInit"); + e.printStackTrace(); + throw new InitializationException(e); + } + } + + @Mod.EventHandler + public void init(FMLInitializationEvent evt) { + try { + ProgressBar progressBar = ProgressManager.push("Initializing NOVA mods", NovaMinecraftPreloader.modClasses.size(), true); + proxy.init(); + nativeConverters.stream().forEachOrdered(Loadable::init); + launcher.init(new FMLProgressBar(progressBar)); + ProgressManager.pop(progressBar); + } catch (Exception e) { + System.out.println("Error during init"); + e.printStackTrace(); + throw new InitializationException(e); + } + } + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent evt) { + try { + ProgressBar progressBar = ProgressManager.push("Post-initializing NOVA mods", NovaMinecraftPreloader.modClasses.size(), true); + Game.recipes().init(); + proxy.postInit(); + nativeConverters.stream().forEachOrdered(Loadable::postInit); + launcher.postInit(new FMLProgressBar(progressBar)); + ProgressManager.pop(progressBar); + } catch (Exception e) { + System.out.println("Error during postInit"); + e.printStackTrace(); + throw new InitializationException(e); + } + } + + @Mod.EventHandler + public void serverStarting(FMLServerStartingEvent event) { + Game.events().publish(new ServerEvent.Start()); + } + + @Mod.EventHandler + public void serverStopping(FMLServerStoppingEvent event) { + Game.events().publish(new ServerEvent.Stop()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/FWClientManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/FWClientManager.java new file mode 100644 index 000000000..f4487085d --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/FWClientManager.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.manager; + +import net.minecraft.client.Minecraft; +import nova.core.entity.Entity; +import nova.core.game.ClientManager; +import nova.core.wrapper.mc.forge.v1_11.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward.BWEntity; + +/** + * @author Calclavia + */ +public class FWClientManager extends ClientManager { + + @Override + public Entity getPlayer() { + return new BWEntity(NovaMinecraft.proxy.getClientPlayer()); + } + + @Override + public boolean isPaused() { + return Minecraft.getMinecraft().isGamePaused(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/MCRetentionManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/MCRetentionManager.java new file mode 100644 index 000000000..81d21cc3b --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/MCRetentionManager.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.manager; + +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.event.world.WorldEvent; +import net.minecraftforge.fml.client.FMLClientHandler; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import nova.core.retention.Data; +import nova.core.retention.Storable; +import nova.core.util.registry.RetentionManager; +import nova.internal.core.Game; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import net.minecraftforge.fml.server.FMLServerHandler; + +/** + * A manager that handles external file saving. + * @author Calclavia + */ +public class MCRetentionManager extends RetentionManager { + + /** + * Last time that the queueSave manager tried to queueSave a file + */ + private long lastSaveMills = 0; + + /** + * Save all storable queued + */ + public void saveAll() { + saveQueue.forEach(this::save); + saveQueue.clear(); + } + + @Override + public void save(String filename, Storable storable) { + Data saveMap = new Data(); + storable.save(saveMap); + saveFile(filename, Game.natives().toNative(saveMap)); + } + + @Override + public void load(String filename, Storable storable) { + NBTTagCompound nbt = loadFile(filename); + storable.load(Game.natives().toNova(nbt)); + } + + /** + * Saves NBT data in the world folder. + * @param file File to save data to + * @param data Data to save + * @return True on success. + */ + public boolean saveFile(File file, NBTTagCompound data) { + try { + File tempFile = new File(file.getParent(), file.getName() + "_tmp.dat"); + + CompressedStreamTools.writeCompressed(data, new FileOutputStream(tempFile)); + + if (file.exists()) { + file.delete(); + } + + tempFile.renameTo(file); + return true; + } catch (Exception e) { + System.out.println("Failed to queueSave " + file.getName() + ".dat!"); + e.printStackTrace(); + return false; + } + } + + public boolean saveFile(File saveDirectory, String filename, NBTTagCompound data) { + return saveFile(new File(saveDirectory, filename + ".dat"), data); + } + + public boolean saveFile(String filename, NBTTagCompound data) { + return saveFile(getSaveDirectory(FMLServerHandler.instance().getServer().getFolderName()), filename, data); + } + + public NBTTagCompound loadFile(File file) { + try { + if (file.exists()) { + return CompressedStreamTools.readCompressed(new FileInputStream(file)); + } else { + return new NBTTagCompound(); + } + } catch (Exception e) { + System.out.println("Failed to load " + file.getName() + ".dat!"); + e.printStackTrace(); + return null; + } + } + + /** + * Reads NBT data from the world folder. + * @param saveDirectory Directory in which the file resides + * @param filename Name of the file + * @return The NBT data + */ + public NBTTagCompound loadFile(File saveDirectory, String filename) { + return loadFile(new File(saveDirectory, filename + ".dat")); + } + + public NBTTagCompound loadFile(String filename) { + return loadFile(getSaveDirectory(FMLServerHandler.instance().getServer().getFolderName()), filename); + } + + @Override + public File getSaveDirectory() { + return getSaveDirectory(FMLServerHandler.instance().getServer().getFolderName()); + } + + public File getSaveDirectory(String worldName) { + File parent = getBaseDirectory(); + + if (FMLCommonHandler.instance().getSide().isClient()) { + parent = new File(getBaseDirectory(), "saves" + File.separator); + } + + return new File(parent, worldName + File.separator); + } + + public File getBaseDirectory() { + if (FMLCommonHandler.instance().getSide().isClient()) { + FMLClientHandler.instance().getClient(); + return FMLClientHandler.instance().getClient().mcDataDir; + } else { + return new File("."); + } + } + + @SubscribeEvent + public void worldSave(WorldEvent evt) { + //Current time milli-seconds is used to prevent the files from saving 20 times when the world loads + if (System.currentTimeMillis() - lastSaveMills > 2000) { + lastSaveMills = System.currentTimeMillis(); + saveAll(); + } + } + + @Override + public void init() { + + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/config/NovaGuiConfig.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/config/NovaGuiConfig.java new file mode 100644 index 000000000..c045c7b35 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/config/NovaGuiConfig.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.manager.config; + +import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.common.config.ConfigElement; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.fml.client.config.GuiConfig; + +/** + * @author Calclavia + */ +public class NovaGuiConfig extends GuiConfig { + public NovaGuiConfig(GuiScreen parentScreen, Configuration config, String modID) { + super(parentScreen, new ConfigElement(config.getCategory(Configuration.CATEGORY_GENERAL)).getChildElements(), modID, false, false, GuiConfig.getAbridgedConfigPath(config.toString())); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/config/NovaGuiFactory.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/config/NovaGuiFactory.java new file mode 100644 index 000000000..2d7cd5345 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/manager/config/NovaGuiFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.manager.config; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.fml.client.IModGuiFactory; + +import java.util.Set; + +/** + * @author Calclavia + */ +public class NovaGuiFactory implements IModGuiFactory { + @Override + public void initialize(Minecraft minecraftInstance) { + + } + + @Override + public Class mainConfigGuiClass() { + return NovaGuiConfig.class; + } + + @Override + public Set runtimeGuiCategories() { + return null; + } + + @Override + public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) { + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/MCPacket.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/MCPacket.java new file mode 100644 index 000000000..2da87aa23 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/MCPacket.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.network; + +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.ByteBufUtils; +import nova.core.entity.component.Player; +import nova.core.network.Packet; + +/** + * Wraps ByteBuf into a NOVA Packet. + * @author Calclavia + */ +public class MCPacket implements Packet { + + public final ByteBuf buf; + public final Player player; + private int id = 0; + + public MCPacket(ByteBuf buf) { + this.buf = buf; + player = null; + } + + public MCPacket(ByteBuf buf, Player player) { + this.buf = buf; + this.player = player; + } + + @Override + public Player player() { + if (player == null) { + throw new RuntimeException("Attempt to get player in packet when it does not exist!"); + } + + return player; + } + + @Override + public int getID() { + return id; + } + + @Override + public Packet setID(int id) { + this.id = id; + return this; + } + + @Override + public Packet writeBoolean(boolean value) { + buf.writeBoolean(value); + return this; + } + + @Override + public Packet writeByte(int value) { + buf.writeByte(value); + return this; + } + + @Override + public Packet writeShort(int value) { + buf.writeShort(value); + return this; + } + + @Override + public Packet writeInt(int value) { + buf.writeInt(value); + return this; + } + + @Override + public Packet writeLong(long value) { + buf.writeLong(value); + return this; + } + + @Override + public Packet writeChar(int value) { + buf.writeChar(value); + return this; + } + + @Override + public Packet writeFloat(float value) { + buf.writeFloat(value); + return this; + } + + @Override + public Packet writeDouble(double value) { + buf.writeDouble(value); + return this; + } + + @Override + public Packet writeString(String value) { + ByteBufUtils.writeUTF8String(buf, value); + return this; + } + + @Override + public Packet writeBytes(byte[] array) { + buf.writeBytes(array); + return this; + } + + @Override + public byte[] readBytes(int length) { + byte[] array = new byte[length]; + for (int i = 0; i < length; i++) + array[i] = buf.readByte(); + return array; + } + + @Override + public boolean readBoolean() { + return buf.readBoolean(); + } + + @Override + public byte readByte() { + return buf.readByte(); + } + + @Override + public short readUnsignedByte() { + return buf.readUnsignedByte(); + } + + @Override + public short readShort() { + return buf.readShort(); + } + + @Override + public int readInt() { + return buf.readInt(); + } + + @Override + public long readUnsignedInt() { + return buf.readUnsignedInt(); + } + + @Override + public long readLong() { + return buf.readLong(); + } + + @Override + public char readChar() { + return buf.readChar(); + } + + @Override + public float readFloat() { + return buf.readFloat(); + } + + @Override + public double readDouble() { + return buf.readDouble(); + } + + @Override + public String readString() { + return ByteBufUtils.readUTF8String(buf); + } + + public void writeTo(ByteBuf other) { + other.writeBytes(buf); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/NovaPacket.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/NovaPacket.java new file mode 100644 index 000000000..61b04541d --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/NovaPacket.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.network.discriminator; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.entity.player.EntityPlayer; +import nova.core.entity.Entity; +import nova.core.entity.component.Player; +import nova.core.network.handler.PacketHandler; +import nova.core.wrapper.mc.forge.v1_11.network.MCPacket; +import nova.core.wrapper.mc.forge.v1_11.network.netty.MCNetworkManager; +import nova.internal.core.Game; + +/** + * NOVA Packet Structure: + * + * 1. Packet Type ID + * 2. Packet Sub ID + * 3. Data + * @author Calclavia + */ +public class NovaPacket extends PacketAbstract { + + @Override + public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { + buffer.writeBytes(data); + } + + @Override + public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { + data = buffer.slice(); + } + + @Override + public void handleClientSide(EntityPlayer player) { + handle(player); + } + + @Override + public void handleServerSide(EntityPlayer player) { + handle(player); + } + + public void handle(EntityPlayer player) { + try { + MCNetworkManager network = (MCNetworkManager) Game.network(); + PacketHandler packetHandler = network.getPacketType(data.readInt()); + int subId = data.readInt(); + MCPacket packet = new MCPacket(data.slice(), ((Entity) Game.natives().toNova(player)).components.get(Player.class)); + //Set the ID of the packet + packet.setID(subId); + packetHandler.read(packet); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/PacketAbstract.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/PacketAbstract.java new file mode 100644 index 000000000..3a866fc07 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/PacketAbstract.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.network.discriminator; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.entity.player.EntityPlayer; +import nova.core.wrapper.mc.forge.v1_11.network.netty.MCNetworkManager; + +/** + * For custom packets extend this Class and register on Mod loading phase + *

+ * Without registering a NPE will be thrown as the {@link MCNetworkManager} won't know how to handle it + *

+ * To send this packet also look at {@link MCNetworkManager#sendToAll(PacketAbstract)} + * And other implementations there. + * @author tgame14, Calclavia + * @since 26/05/14 + */ +public abstract class PacketAbstract { + public ByteBuf data = Unpooled.buffer(); + EntityPlayer sender = null; + + /** + * Encode the packet data into the ByteBuf stream. Complex data sets may need specific data handlers + * @param ctx channel context + * @param buffer the buffer to encode into + * @see net.minecraftforge.fml.common.network.ByteBufUtils + */ + public abstract void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer); + + /** + * Decode the packet data from the ByteBuf stream. Complex data sets may need specific data handlers + * @param ctx channel context + * @param buffer the buffer to decode from + * @see net.minecraftforge.fml.common.network.ByteBufUtils + */ + public abstract void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer); + + /** + * Handle a packet on the client side. Note this occurs after decoding has completed. + * @param player the player reference + */ + public void handleClientSide(EntityPlayer player) { + throw new UnsupportedOperationException("Unsupported operation for Packet: " + getClass().getSimpleName()); + } + + /** + * Handle a packet on the server side. Note this occurs after decoding has completed. + * @param player the player reference + */ + public void handleServerSide(EntityPlayer player) { + throw new UnsupportedOperationException("Unsupported operation for Packet: " + getClass().getSimpleName()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/PacketPlayerItem.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/PacketPlayerItem.java new file mode 100644 index 000000000..3d4f75858 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/discriminator/PacketPlayerItem.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.network.discriminator; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import nova.core.network.Syncable; +import nova.core.wrapper.mc.forge.v1_11.network.MCPacket; + +/** + * A packet handler for players who are currently holding their item. + * @author Calclavia + */ +//TODO: Move to NOVA Core +public class PacketPlayerItem extends PacketAbstract { + public int slotId; + + public PacketPlayerItem() { + + } + + public PacketPlayerItem(int slotId) { + this.slotId = slotId; + } + + public PacketPlayerItem(EntityPlayer player) { + this(player.inventory.currentItem); + } + + @Override + public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { + buffer.writeInt(slotId); + buffer.writeBytes(data); + } + + @Override + public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { + slotId = buffer.readInt(); + data = buffer.slice(); + } + + @Override + public void handleClientSide(EntityPlayer player) { + ItemStack stack = player.inventory.getStackInSlot(this.slotId); + + if (stack != null && stack.getItem() instanceof Syncable) { + MCPacket mcPacket = new MCPacket(data); + mcPacket.setID(data.readInt()); + ((Syncable) stack.getItem()).read(mcPacket); + } + } + + @Override + public void handleServerSide(EntityPlayer player) { + ItemStack stack = player.inventory.getStackInSlot(this.slotId); + + if (stack != null && stack.getItem() instanceof Syncable) { + MCPacket mcPacket = new MCPacket(data); + mcPacket.setID(data.readInt()); + ((Syncable) stack.getItem()).read(mcPacket); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/ChannelHandler.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/ChannelHandler.java new file mode 100644 index 000000000..d49859e0a --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/ChannelHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.network.netty; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraftforge.fml.common.network.FMLIndexedMessageToMessageCodec; +import nova.core.wrapper.mc.forge.v1_11.network.discriminator.NovaPacket; +import nova.core.wrapper.mc.forge.v1_11.network.discriminator.PacketAbstract; +import nova.core.wrapper.mc.forge.v1_11.network.discriminator.PacketPlayerItem; + +/** + * Handles the channel and discriminators. + * @author Calclavia + */ +public class ChannelHandler extends FMLIndexedMessageToMessageCodec { + public ChannelHandler() { + addDiscriminator(0, NovaPacket.class); + addDiscriminator(1, PacketPlayerItem.class); + } + + @Override + public void encodeInto(ChannelHandlerContext ctx, PacketAbstract packet, ByteBuf target) throws Exception { + packet.encodeInto(ctx, target); + } + + @Override + public void decodeInto(ChannelHandlerContext ctx, ByteBuf source, PacketAbstract packet) { + packet.decodeInto(ctx, source); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/MCNetworkManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/MCNetworkManager.java new file mode 100644 index 000000000..05922cc1e --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/MCNetworkManager.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.network.netty; + +import io.netty.buffer.Unpooled; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.INetHandler; +import net.minecraft.network.Packet; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.network.FMLEmbeddedChannel; +import net.minecraftforge.fml.common.network.FMLOutboundHandler; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nova.core.entity.component.Player; +import nova.core.network.NetworkManager; +import nova.core.network.Syncable; +import nova.core.wrapper.mc.forge.v1_11.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11.network.MCPacket; +import nova.core.wrapper.mc.forge.v1_11.network.discriminator.NovaPacket; +import nova.core.wrapper.mc.forge.v1_11.network.discriminator.PacketAbstract; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward.BWEntity; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.EnumMap; + +/** + * The implementation of NetworkManager that will be injected. + * @author Calclavia + * @since 26/05/14 + */ +public class MCNetworkManager extends NetworkManager { + public final String channel = NovaMinecraft.id; + public final EnumMap channelEnumMap = NetworkRegistry.INSTANCE.newChannel(channel, new ChannelHandler(), new MCPacketHandler()); + + public Packet toMCPacket(PacketAbstract packet) { + return channelEnumMap.get(FMLCommonHandler.instance().getEffectiveSide()).generatePacketFrom(packet); + } + + @Override + public nova.core.network.Packet newPacket() { + return new MCPacket(Unpooled.buffer()); + } + + @Override + public void sendPacket(nova.core.network.Packet packet) { + //Wrap the packet in NOVA's discriminator + PacketAbstract discriminator = new NovaPacket(); + //Write packet + discriminator.data.writeBytes(((MCPacket) packet).buf); + + if (isServer()) { + sendToAll(discriminator); + } else { + sendToServer(discriminator); + } + } + + public PacketAbstract writePacket(int id, Syncable sender) { + PacketAbstract discriminator = new NovaPacket(); + nova.core.network.Packet packet = newPacket(); + packet.setID(id); + + //Write packet + writePacket(sender, packet); + discriminator.data.writeBytes(((MCPacket) packet).buf); + return discriminator; + } + + @Override + public void sendChat(Player player, String message) { + if (player instanceof BWEntity.MCPlayer) { + ((BWEntity.MCPlayer) player).entity.sendMessage(new TextComponentString(message)); + } + } + + @Override + public boolean isServer() { + return FMLCommonHandler.instance().getEffectiveSide().isServer(); + } + + /** + * @param packet the packet to send to the player + * @param player the player MP object + */ + public void sendToPlayer(PacketAbstract packet, EntityPlayerMP player) { + this.channelEnumMap.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER); + this.channelEnumMap.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player); + this.channelEnumMap.get(Side.SERVER).writeAndFlush(packet); + } + + /** + * @param packet the packet to send to the players in the dimension + * @param dimId the dimension id to send to. + */ + public void sendToAllInDimension(PacketAbstract packet, int dimId) { + this.channelEnumMap.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.DIMENSION); + this.channelEnumMap.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(dimId); + this.channelEnumMap.get(Side.SERVER).writeAndFlush(packet); + } + + public void sendToAllInDimension(PacketAbstract packet, World world) { + sendToAllInDimension(packet, world.provider.getDimension()); + } + + /** + * sends to all clients connected to the server + * @param packet the packet to send. + */ + public void sendToAll(PacketAbstract packet) { + this.channelEnumMap.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL); + this.channelEnumMap.get(Side.SERVER).writeAndFlush(packet); + } + + public void sendToAllAround(PacketAbstract message, NetworkRegistry.TargetPoint point) { + this.channelEnumMap.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT); + this.channelEnumMap.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point); + this.channelEnumMap.get(Side.SERVER).writeAndFlush(message); + } + + public void sendToAllAround(PacketAbstract message, World world, Vector3D point, double range) { + sendToAllAround(message, world, point.getX(), point.getY(), point.getZ(), range); + } + + public void sendToAllAround(PacketAbstract message, TileEntity tile) { + sendToAllAround(message, tile, 64); + } + + public void sendToAllAround(PacketAbstract message, TileEntity tile, double range) { + sendToAllAround(message, tile.getWorld(), tile.getPos().getX(), tile.getPos().getY(), tile.getPos().getZ(), range); + } + + public void sendToAllAround(PacketAbstract message, World world, double x, double y, double z, double range) { + sendToAllAround(message, new NetworkRegistry.TargetPoint(world.provider.getDimension(), x, y, z, range)); + } + + @SideOnly(Side.CLIENT) + public void sendToServer(PacketAbstract packet) { + this.channelEnumMap.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.TOSERVER); + this.channelEnumMap.get(Side.CLIENT).writeAndFlush(packet); + } +} + + diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/MCPacketHandler.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/MCPacketHandler.java new file mode 100644 index 000000000..994303ffe --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/network/netty/MCPacketHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.network.netty; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import net.minecraft.network.INetHandler; +import net.minecraft.network.NetHandlerPlayServer; +import net.minecraftforge.fml.client.FMLClientHandler; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import nova.core.wrapper.mc.forge.v1_11.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11.network.discriminator.PacketAbstract; + +/** + * @author tgame14 + * @since 31/05/14 + */ +@ChannelHandler.Sharable +public class MCPacketHandler extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext ctx, PacketAbstract packet) throws Exception { + INetHandler netHandler = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get(); + + switch (FMLCommonHandler.instance().getEffectiveSide()) { + case CLIENT: + FMLClientHandler.instance().getClient().addScheduledTask(() -> packet.handleClientSide(NovaMinecraft.proxy.getClientPlayer())); + break; + case SERVER: + FMLCommonHandler.instance().getMinecraftServerInstance().addScheduledTask(() -> packet.handleServerSide(((NetHandlerPlayServer) netHandler).playerEntity)); + break; + default: + break; + } + + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MCCraftingGrid.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MCCraftingGrid.java new file mode 100644 index 000000000..0eafaf8b9 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MCCraftingGrid.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.Slot; +import net.minecraft.inventory.SlotCrafting; +import net.minecraft.item.ItemStack; +import nova.core.entity.component.Player; +import nova.core.recipes.crafting.CraftingGrid; +import nova.core.wrapper.mc.forge.v1_11.util.ReflectionUtil; +import nova.core.wrapper.mc.forge.v1_11.util.WrapUtility; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.ItemConverter; +import nova.internal.core.Game; + +import java.util.List; +import java.util.Optional; + +/** + * @author Stan Hebben + */ +public class MCCraftingGrid implements CraftingGrid { + private static final ThreadLocal cache = new ThreadLocal(); + private static final ThreadLocal cache2 = new ThreadLocal(); + private final IInventory inventory; + private final Optional player; + private final EntityPlayer playerOrig; + private int width; + private int height; + private nova.core.item.Item[] stacks; + private ItemStack[] original; + private int numberOfStacks; + + private MCCraftingGrid(InventoryCrafting inventory) { + this.inventory = inventory; + width = height = (int) Math.sqrt(inventory.getSizeInventory()); + stacks = new nova.core.item.Item[width * height]; + original = new ItemStack[stacks.length]; + numberOfStacks = 0; + update(); + + Container container = ReflectionUtil.getCraftingContainer(inventory); + if (container != null) { + List slots = container.inventorySlots; + if (!slots.isEmpty() && slots.get(0) instanceof SlotCrafting) { + SlotCrafting slotCrafting = (SlotCrafting) slots.get(0); + playerOrig = ReflectionUtil.getCraftingSlotPlayer(slotCrafting); + player = WrapUtility.getNovaPlayer(playerOrig); + } else { + playerOrig = null; + player = null; + } + } else { + playerOrig = null; + player = null; + } + } + + public MCCraftingGrid(IInventory inventory, EntityPlayer player) { + this.inventory = inventory; + width = height = (int) Math.sqrt(inventory.getSizeInventory()); + stacks = new nova.core.item.Item[width * height]; + original = new ItemStack[stacks.length]; + numberOfStacks = 0; + update(); + + playerOrig = player; + this.player = WrapUtility.getNovaPlayer(player); + } + + public static MCCraftingGrid get(InventoryCrafting inventory) { + if (cache.get() == null || cache.get().inventory != inventory) { + MCCraftingGrid result = new MCCraftingGrid(inventory); + cache.set(result); + return result; + } else { + MCCraftingGrid result = cache.get(); + result.update(); + return result; + } + } + + public static MCCraftingGrid get(IInventory inventory, EntityPlayer player) { + if (cache2.get() == null || cache2.get().inventory != inventory || cache2.get().playerOrig != player) { + MCCraftingGrid result = new MCCraftingGrid(inventory, player); + cache2.set(result); + return result; + } else { + MCCraftingGrid result = cache2.get(); + result.update(); + return result; + } + } + + private void update() { + if (inventory.getSizeInventory() != original.length) { + width = height = (int) Math.sqrt(inventory.getSizeInventory()); + stacks = new nova.core.item.Item[inventory.getSizeInventory()]; + original = new ItemStack[stacks.length]; + numberOfStacks = 0; + } + + for (int i = 0; i < inventory.getSizeInventory(); i++) { + if (changed(i)) { + //System.out.println("Slot " + i + " changed"); + original[i] = inventory.getStackInSlot(i); + if (inventory.getStackInSlot(i) != null) { + if (stacks[i] == null) { + numberOfStacks++; + } + + stacks[i] = Game.natives().toNova(original[i]); + } else { + if (stacks[i] != null) { + numberOfStacks--; + } + + stacks[i] = null; + } + } + } + //System.out.println("Num stack count: " + numberOfStacks); + } + + @Override + public Optional getPlayer() { + return player; + } + + @Override + public int size() { + return width * height; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int countFilledStacks() { + return numberOfStacks; + } + + @Override + public Optional getStack(int i) { + return Optional.ofNullable(stacks[i]); + } + + @Override + public Optional getStack(int x, int y) { + return Optional.ofNullable(stacks[y * width + x]); + } + + @Override + public boolean setStack(int x, int y, Optional stack) { + //System.out.println("SetStack(" + x + ", " + y + ") " + stack); + + int ix = y * width + x; + if (stack.isPresent()) { + if (!stack.get().equals(stacks[ix])) { + inventory.setInventorySlotContents(ix, Game.natives().toNative(stack.get())); + + if (stacks[ix] == null) { + numberOfStacks++; + } + + stacks[ix] = stack.get(); + } + } else { + numberOfStacks--; + inventory.setInventorySlotContents(ix, null); + stacks[ix] = null; + } + + return true; + } + + @Override + public boolean setStack(int i, Optional stack) { + //System.out.println("SetStack(" + i + ") " + stack); + + if (stack.isPresent()) { + if (stacks[i] == null) { + numberOfStacks++; + } + + inventory.setInventorySlotContents(i, Game.natives().toNative(stack.get())); + stacks[i] = stack.get(); + } else { + if (stacks[i] == null) { + return true; + } + + numberOfStacks--; + inventory.setInventorySlotContents(i, null); + stacks[i] = null; + } + + return true; + } + + @Override + public void giveBack(nova.core.item.Item itemStack) { + playerOrig.inventory.addItemStackToInventory(ItemConverter.instance().toNative(itemStack)); + } + + @Override + public String getTopology() { + return CraftingGrid.topologySquare; + } + + @Override + public String getType() { + return CraftingGrid.typeCrafting; + } + + private boolean changed(int i) { + if (original[i] != inventory.getStackInSlot(i)) { + return true; + } + + if (original[i] != null && stacks[i].count() != original[i].getCount()) { + return true; + } + + return false; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MCCraftingRecipe.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MCCraftingRecipe.java new file mode 100644 index 000000000..8b3a53453 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MCCraftingRecipe.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.item.crafting.IRecipe; +import nova.core.item.Item; +import nova.core.recipes.crafting.CraftingGrid; +import nova.core.recipes.crafting.CraftingRecipe; +import nova.internal.core.Game; + +import java.util.Optional; + +/** + * @author Stan Hebben + */ +public class MCCraftingRecipe implements CraftingRecipe { + private final IRecipe recipe; + + public MCCraftingRecipe(IRecipe recipe) { + this.recipe = recipe; + } + + @Override + public boolean matches(CraftingGrid craftingGrid) { + // TODO: supply world somehow? + return recipe.matches(new NovaCraftingGrid(craftingGrid), null); + } + + @Override + public Optional getCraftingResult(CraftingGrid craftingGrid) { + return Game.natives().toNova(recipe.getCraftingResult(new NovaCraftingGrid(craftingGrid))); + } + + @Override + public void consumeItems(CraftingGrid craftingGrid) { + // not supported + } + + @Override + public Optional getNominalOutput() { + return Game.natives().toNova(recipe.getRecipeOutput()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MinecraftItemIngredient.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MinecraftItemIngredient.java new file mode 100644 index 000000000..f430a58f0 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MinecraftItemIngredient.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import nova.core.item.Item; +import nova.core.recipes.crafting.SpecificItemIngredient; +import nova.internal.core.Game; + +/** + * @author Stan Hebben + */ +public class MinecraftItemIngredient extends SpecificItemIngredient { + public MinecraftItemIngredient(net.minecraft.item.ItemStack itemStack) { + super(((Item) Game.natives().toNova(itemStack)).getID()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MinecraftRecipeRegistry.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MinecraftRecipeRegistry.java new file mode 100644 index 000000000..af3f96b4a --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/MinecraftRecipeRegistry.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraftforge.oredict.RecipeSorter; +import net.minecraftforge.oredict.RecipeSorter.Category; +import nova.core.event.RecipeEvent; +import nova.core.recipes.RecipeManager; +import nova.core.recipes.crafting.CraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11.util.ReflectionUtil; +import nova.internal.core.Game; + +import java.util.AbstractList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.stream.Stream; + +/** + * Created by Stan on 1/02/2015. + */ +public class MinecraftRecipeRegistry { + public static final MinecraftRecipeRegistry instance = new MinecraftRecipeRegistry(); + + private final Map forwardWrappers = new HashMap<>(); + private final Map backwardWrappers = new HashMap<>(); + + private MinecraftRecipeRegistry() { + } + + public void registerRecipes() { + long startTime = System.currentTimeMillis(); + + RecipeManager recipeManager = Game.recipes(); + + List recipes = CraftingManager.getInstance().getRecipeList(); + for (IRecipe recipe : recipes) { + CraftingRecipe converted = convert(recipe); + if (converted != null) { + recipeManager.addRecipe(converted); + backwardWrappers.put(recipe, converted); + forwardWrappers.put(converted, recipe); + } + } + + ReflectionUtil.setCraftingRecipeList(new RecipeListWrapper(recipes)); + + System.out.println("Initialized recipes in " + (System.currentTimeMillis() - startTime) + " ms"); + + RecipeSorter.register("nova:shaped", ShapedRecipeBasic.class, Category.SHAPED, "before:forge:shapedore"); + RecipeSorter.register("nova:shaped.oredict", ShapedRecipeOre.class, Category.SHAPED, "after:nova:shaped after:minecraft:shaped before:minecraft:shapeless"); + + RecipeSorter.register("nova:shapeless", ShapelessRecipeBasic.class, Category.SHAPELESS, "after:minecraft:shapeless before:forge:shapelessore"); + RecipeSorter.register("nova:shapeless.oredict", ShapelessRecipeOre.class, Category.SHAPELESS, "after:nova:shapeless after:minecraft:shapeless"); + + RecipeSorter.register("nova:unknown", NovaCraftingRecipe.class, Category.UNKNOWN, ""); + + recipeManager.whenRecipeAdded(CraftingRecipe.class, this::onNOVARecipeAdded); + recipeManager.whenRecipeRemoved(CraftingRecipe.class, this::onNOVARecipeRemoved); + } + + private CraftingRecipe convert(IRecipe recipe) { + return RecipeConverter.toNova(recipe); + } + + private IRecipe convert(CraftingRecipe recipe) { + return RecipeConverter.toMinecraft(recipe); + } + + private void onNOVARecipeAdded(RecipeEvent.Add e) { + CraftingRecipe recipe = e.recipe; + if (forwardWrappers.containsKey(recipe)) { + return; + } + + IRecipe minecraftRecipe = convert(recipe); + + backwardWrappers.put(minecraftRecipe, recipe); + forwardWrappers.put(recipe, minecraftRecipe); + + CraftingManager.getInstance().getRecipeList().add(minecraftRecipe); + } + + private void onNOVARecipeRemoved(RecipeEvent.Remove e) { + IRecipe minecraftRecipe = forwardWrappers.get(e.recipe); + + forwardWrappers.remove(e.recipe); + backwardWrappers.remove(minecraftRecipe); + + CraftingManager.getInstance().getRecipeList().remove(minecraftRecipe); + } + + private void onMinecraftRecipeAdded(IRecipe recipe) { + if (backwardWrappers.containsKey(recipe)) { + return; + } + + CraftingRecipe novaRecipe = convert(recipe); + + backwardWrappers.put(recipe, novaRecipe); + forwardWrappers.put(novaRecipe, recipe); + + Game.recipes().addRecipe(novaRecipe); + } + + private void onMinecraftRecipeRemoved(IRecipe recipe) { + CraftingRecipe novaRecipe = backwardWrappers.get(recipe); + + forwardWrappers.remove(novaRecipe); + backwardWrappers.remove(recipe); + + Game.recipes().removeRecipe(novaRecipe); + } + + private class RecipeListWrapper extends AbstractList { + private final List original; + + public RecipeListWrapper(List original) { + this.original = original; + } + + @Override + public int size() { + return original.size(); + } + + @Override + public boolean isEmpty() { + return original.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return original.contains(o); + } + + @Override + public Iterator iterator() { + return original.iterator(); + } + + @Override + public void forEach(Consumer action) { + original.forEach(action); + } + + @Override + public Object[] toArray() { + return original.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return original.toArray(a); + } + + @Override + public boolean add(IRecipe iRecipe) { + boolean result = original.add(iRecipe); + if (result && !backwardWrappers.containsKey(iRecipe)) { + onMinecraftRecipeAdded(iRecipe); + } + + return result; + } + + @Override + public boolean remove(Object o) { + if (!backwardWrappers.containsKey(o)) { + return false; + } + + boolean result = original.remove(o); + if (result) { + onMinecraftRecipeRemoved((IRecipe) o); + } + + return result; + } + + @Override + public boolean containsAll(Collection c) { + return original.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + boolean result = false; + for (IRecipe recipe : c) { + result |= add(recipe); + } + return result; + } + + @Override + public boolean addAll(int index, Collection c) { + for (IRecipe recipe : c) { + add(index, recipe); + index++; + } + + return !c.isEmpty(); + } + + @Override + public boolean removeAll(Collection c) { + boolean result = false; + for (Object o : c) { + result |= c.remove(o); + } + return result; + } + + @Override + public boolean retainAll(Collection c) { + return false; + } + + @Override + public void sort(Comparator c) { + original.sort(c); + } + + @Override + public void clear() { + // one would have to be a mad scientist to use this operation... but ok + + for (IRecipe recipe : original) { + onMinecraftRecipeRemoved(recipe); + } + + original.clear(); + } + + @Override + public IRecipe get(int index) { + return original.get(index); + } + + @Override + public IRecipe set(int index, IRecipe element) { + IRecipe current = original.get(index); + onMinecraftRecipeRemoved(current); + + original.set(index, element); + onMinecraftRecipeAdded(element); + + return current; + } + + @Override + public void add(int index, IRecipe element) { + original.add(index, element); + onMinecraftRecipeAdded(element); + } + + @Override + public IRecipe remove(int index) { + IRecipe current = original.remove(index); + onMinecraftRecipeRemoved(current); + return current; + } + + @Override + public int indexOf(Object o) { + return original.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return original.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return original.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return original.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return new RecipeListWrapper(original.subList(fromIndex, toIndex)); + } + + @Override + public Spliterator spliterator() { + return original.spliterator(); + } + + @Override + public Stream stream() { + return original.stream(); + } + + @Override + public Stream parallelStream() { + return original.parallelStream(); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingGrid.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingGrid.java new file mode 100644 index 000000000..29d385bee --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingGrid.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.inventory.InventoryCrafting; +import nova.core.recipes.crafting.CraftingGrid; + +public class NovaCraftingGrid extends InventoryCrafting { + private final CraftingGrid craftingGrid; + + public NovaCraftingGrid(CraftingGrid craftingGrid) { + super(new NovaCraftingGridContainer(craftingGrid), craftingGrid.getWidth(), craftingGrid.getHeight()); + this.craftingGrid = craftingGrid; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingGridContainer.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingGridContainer.java new file mode 100644 index 000000000..2059423a5 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingGridContainer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import nova.core.recipes.crafting.CraftingGrid; + +/** + * TODO: complete this class. without it, modded recipes will not work when crafted from NOVA mods. + * @author Stan Hebben + */ +public class NovaCraftingGridContainer extends Container { + private final CraftingGrid craftingGrid; + + public NovaCraftingGridContainer(CraftingGrid craftingGrid) { + this.craftingGrid = craftingGrid; + } + + @Override + public boolean canInteractWith(EntityPlayer entityPlayer) { + return true; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingRecipe.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingRecipe.java new file mode 100644 index 000000000..c04a4c622 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/NovaCraftingRecipe.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.NonNullList; +import net.minecraft.world.World; +import nova.core.item.Item; +import nova.core.recipes.crafting.CraftingRecipe; +import nova.internal.core.Game; + +import java.util.Optional; + +public class NovaCraftingRecipe implements IRecipe { + private final CraftingRecipe recipe; + + public NovaCraftingRecipe(CraftingRecipe recipe) { + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventoryCrafting, World world) { + return recipe.matches(MCCraftingGrid.get(inventoryCrafting)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventoryCrafting) { + Optional craftingResult = recipe.getCraftingResult(MCCraftingGrid.get(inventoryCrafting)); + if (craftingResult.isPresent()) { + return Game.natives().toNative(craftingResult.get()); + } else { + return null; + } + } + + @Override + public int getRecipeSize() { + return 1; + } + + @Override + public ItemStack getRecipeOutput() { + Optional nominalOutput = recipe.getNominalOutput(); + if (nominalOutput.isPresent()) { + return Game.natives().toNative(nominalOutput.get()); + } + return null; + } + + @Override + public NonNullList getRemainingItems(InventoryCrafting inv) { + return NonNullList.create(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/RecipeConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/RecipeConverter.java new file mode 100644 index 000000000..eb711986f --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/RecipeConverter.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraftforge.oredict.ShapedOreRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; +import nova.core.item.Item; +import nova.core.recipes.crafting.CraftingRecipe; +import nova.core.recipes.crafting.ItemIngredient; +import nova.core.recipes.crafting.OreItemIngredient; +import nova.core.recipes.crafting.ShapedCraftingRecipe; +import nova.core.recipes.crafting.ShapelessCraftingRecipe; +import nova.core.recipes.crafting.SpecificItemIngredient; +import nova.core.wrapper.mc.forge.v1_11.util.ReflectionUtil; +import nova.internal.core.Game; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +/** + * Wraps Minecraft crafting recipes to NOVA crafting recipes and vice versa. + * + * Although a naive implementation could wrap NOVA recipes into its own recipe class and forward that, mods like NEI + * won't be able to handle those recipes. Hence we wrap them into ShapedRecipes / ShapelessRecipes / ShapedOreRecipes and ShapelessOreRecipes + * as much as possible. Only when that is not possible (a rare case, in practice) the generic wrapper is used. + * + * The reverse is also done, such that mods listening to NOVA ShapedCraftingRecipes and ShapelessCraftingRecipes would be + * given the proper information and be informed of their registration, if desired. + * @author Stan Hebben + */ +public class RecipeConverter { + public static final int TYPE_ADVANCED = 0; + public static final int TYPE_ORE = 1; + public static final int TYPE_BASIC = 2; + + private RecipeConverter() { + } + + private static int getIngredientType(ItemIngredient ingredient) { + if (ingredient instanceof SpecificItemIngredient) { + return TYPE_BASIC; + } else if (ingredient instanceof OreItemIngredient) { + return TYPE_ORE; + } else { + return TYPE_ADVANCED; + } + } + + private static Object getInternal(ItemIngredient ingredient) { + if (ingredient instanceof SpecificItemIngredient) { + return wrapSpecific((SpecificItemIngredient) ingredient); + } else if (ingredient instanceof OreItemIngredient) { + return ((OreItemIngredient) ingredient).getName(); + } + + return null; + } + + private static ItemIngredient getIngredient(Object ingredient) { + if (ingredient == null) { + return null; + } else if (ingredient instanceof ItemStack) { + return ((ItemStack) ingredient).isEmpty() ? null : ItemIngredient.forItem(net.minecraft.item.Item.REGISTRY.getNameForObject(((ItemStack) ingredient).getItem()).toString()); + } else if (ingredient instanceof String) { + return ItemIngredient.forDictionary((String) ingredient); + } else if (ingredient instanceof List) { + @SuppressWarnings("unchecked") + String oreDictEntry = findOreDictEntryFor((List) ingredient); + if (oreDictEntry == null) { + return null; + } + + return new OreItemIngredient(oreDictEntry); + } else { + return null; + } + } + + private static String findOreDictEntryFor(List ingredient) { + for (String key : net.minecraftforge.oredict.OreDictionary.getOreNames()) { + if (net.minecraftforge.oredict.OreDictionary.getOres(key).equals(ingredient)) { + return key; + } + } + + return null; + } + + private static ItemStack wrapSpecific(SpecificItemIngredient ingredient) { + for (Item item : ingredient.getExampleItems().get()) { + return Game.natives().toNative(item.getFactory().build()); + } + + throw new AssertionError("this can't be!"); + } + + private static int getRecipeType(ItemIngredient[] ingredients) { + int type = TYPE_BASIC; + for (ItemIngredient ingredient : ingredients) { + type = Math.min(type, getIngredientType(ingredient)); + } + return type; + } + + public static IRecipe toMinecraft(CraftingRecipe recipe) { + if (recipe instanceof ShapedCraftingRecipe) { + return convert((ShapedCraftingRecipe) recipe); + } else if (recipe instanceof ShapelessCraftingRecipe) { + return convert((ShapelessCraftingRecipe) recipe); + } else { + return new NovaCraftingRecipe(recipe); + } + } + + public static IRecipe convert(ShapelessCraftingRecipe recipe) { + ItemIngredient[] ingredients = recipe.getIngredients(); + int type = getRecipeType(ingredients); + + switch (type) { + case TYPE_BASIC: { + ItemStack[] items = new ItemStack[ingredients.length]; + for (int i = 0; i < ingredients.length; i++) { + items[i] = wrapSpecific((SpecificItemIngredient) ingredients[i]); + } + return new ShapelessRecipeBasic(items, recipe); + } + case TYPE_ORE: { + Object[] items = new Object[ingredients.length]; + for (int i = 0; i < ingredients.length; i++) { + items[i] = getInternal(ingredients[i]); + } + return new ShapelessRecipeOre(items, recipe); + } + default: + return new NovaCraftingRecipe(recipe); + } + } + + public static IRecipe convert(ShapedCraftingRecipe recipe) { + ItemIngredient[] ingredients = recipe.getIngredients(); + int[] posx = recipe.getIngredientsX(); + int[] posy = recipe.getIngredientsY(); + + // determine recipe type + int type = getRecipeType(ingredients); + + // construct recipe + switch (type) { + case TYPE_BASIC: { + ItemStack[] basicIngredients = new ItemStack[recipe.getHeight() * recipe.getWidth()]; + for (int i = 0; i < ingredients.length; i++) { + basicIngredients[posx[i] + posy[i] * recipe.getWidth()] = wrapSpecific((SpecificItemIngredient) ingredients[i]); + } + + return new ShapedRecipeBasic(basicIngredients, recipe); + } + case TYPE_ORE: { + Object[] converted = new Object[recipe.getHeight() * recipe.getWidth()]; + for (int i = 0; i < ingredients.length; i++) { + converted[posx[i] + posy[i] * recipe.getWidth()] = getInternal(ingredients[i]); + } + + // arguments contents: + // 1) recipe patterns + // 2) characters + ingredients + + int counter = 0; + String[] parts = new String[recipe.getHeight()]; + ArrayList rarguments = new ArrayList<>(); + for (int i = 0; i < recipe.getHeight(); i++) { + char[] pattern = new char[recipe.getWidth()]; + for (int j = 0; j < recipe.getWidth(); j++) { + int off = i * recipe.getWidth() + j; + if (converted[off] == null) { + pattern[j] = ' '; + } else { + pattern[j] = (char) ('A' + counter); + rarguments.add(pattern[j]); + rarguments.add(converted[off]); + counter++; + } + } + parts[i] = new String(pattern); + } + + rarguments.addAll(0, Arrays.asList(parts)); + + return new ShapedRecipeOre(rarguments.toArray(), recipe); + } + default: + return new NovaCraftingRecipe(recipe); + } + } + + public static CraftingRecipe toNova(IRecipe recipe) { + ItemStack recipeOutput = recipe.getRecipeOutput(); + Item output; + if (recipeOutput == null) { + output = null; + } else { + output = Game.natives().toNova(recipeOutput); + } + + if (recipe instanceof ShapelessRecipes) { + ShapelessRecipes shapeless = (ShapelessRecipes) recipe; + + ItemIngredient[] ingredients = new ItemIngredient[shapeless.recipeItems.size()]; + for (int i = 0; i < ingredients.length; i++) { + ingredients[i] = getIngredient(shapeless.recipeItems.get(i)); + } + + return new ShapelessCraftingRecipe(output, ingredients); + } else if (recipe instanceof ShapedRecipes) { + ShapedRecipes shaped = (ShapedRecipes) recipe; + + Optional[][] ingredients = new Optional[shaped.recipeHeight][shaped.recipeWidth]; + for (int i = 0; i < shaped.recipeHeight; i++) { + for (int j = 0; j < shaped.recipeWidth; j++) { + ingredients[i][j] = Optional.ofNullable(getIngredient(shaped.recipeItems[i * shaped.recipeWidth + j])); + } + } + + return new ShapedCraftingRecipe(output, ingredients, false); + } else if (recipe instanceof ShapedOreRecipe) { + ShapedOreRecipe shaped = (ShapedOreRecipe) recipe; + + int width = ReflectionUtil.getShapedOreRecipeWidth(shaped); + int height = recipe.getRecipeSize() / width; + + Optional[][] recipeIngredients = new Optional[height][width]; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + recipeIngredients[i][j] = Optional.ofNullable(getIngredient(shaped.getInput()[i * width + j])); + } + } + + return new ShapedCraftingRecipe(output, recipeIngredients, false); + } else if (recipe instanceof ShapelessOreRecipe) { + ShapelessOreRecipe shapeless = (ShapelessOreRecipe) recipe; + + ItemIngredient[] ingredients = new ItemIngredient[shapeless.getRecipeSize()]; + for (int i = 0; i < ingredients.length; i++) { + ingredients[i] = getIngredient(shapeless.getInput().get(i)); + } + + return new ShapelessCraftingRecipe(output, ingredients); + } else { + return new MCCraftingRecipe(recipe); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapedRecipeBasic.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapedRecipeBasic.java new file mode 100644 index 000000000..8a8f4a40a --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapedRecipeBasic.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ShapedRecipes; +import net.minecraft.world.World; +import nova.core.recipes.crafting.ShapedCraftingRecipe; +import nova.internal.core.Game; + +import java.util.Optional; + +/** + * @author Stan Hebben + */ +public class ShapedRecipeBasic extends ShapedRecipes { + private final ShapedCraftingRecipe recipe; + + public ShapedRecipeBasic(ItemStack[] basicInputs, ShapedCraftingRecipe recipe) { + super(recipe.getWidth(), recipe.getHeight(), basicInputs, recipe.getNominalOutput().isPresent() ? Game.natives().toNative(recipe.getNominalOutput().get()) : null); + + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + Optional result = recipe.getCraftingResult(MCCraftingGrid.get(inventory)); + if (result.isPresent()) { + return Game.natives().toNative(result.get()); + } + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapedRecipeOre.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapedRecipeOre.java new file mode 100644 index 000000000..f7c9b1c77 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapedRecipeOre.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.oredict.ShapedOreRecipe; +import nova.core.item.Item; +import nova.core.recipes.crafting.ShapedCraftingRecipe; +import nova.internal.core.Game; + +import java.util.Optional; + +/** + * @author Stan + */ +public class ShapedRecipeOre extends ShapedOreRecipe { + private final ShapedCraftingRecipe recipe; + + public ShapedRecipeOre(Object[] contents, ShapedCraftingRecipe recipe) { + super((ItemStack) Game.natives().toNative(recipe.getNominalOutput().get()), contents); + + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + Optional craftingResult = recipe.getCraftingResult(MCCraftingGrid.get(inventory)); + if (craftingResult.isPresent()) { + return ((ItemStack) Game.natives().toNative(craftingResult.get())).copy(); + } + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapelessRecipeBasic.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapelessRecipeBasic.java new file mode 100644 index 000000000..60f24670d --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapelessRecipeBasic.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraft.world.World; +import nova.core.item.Item; +import nova.core.recipes.crafting.ShapelessCraftingRecipe; +import nova.internal.core.Game; + +import java.util.Arrays; +import java.util.Optional; + +/** + * @author Stan + */ +public class ShapelessRecipeBasic extends ShapelessRecipes { + private final ShapelessCraftingRecipe recipe; + + public ShapelessRecipeBasic(ItemStack[] ingredients, ShapelessCraftingRecipe recipe) { + super(recipe.getNominalOutput().isPresent() ? Game.natives().toNative(recipe.getNominalOutput().get()) : null, Arrays.asList(ingredients)); + + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + Optional craftingResult = recipe.getCraftingResult(MCCraftingGrid.get(inventory)); + if (craftingResult.isPresent()) { + return Game.natives().toNative(craftingResult.get()); + } + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapelessRecipeOre.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapelessRecipeOre.java new file mode 100644 index 000000000..25aed3f64 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/recipes/ShapelessRecipeOre.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.recipes; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.oredict.ShapelessOreRecipe; +import nova.core.item.Item; +import nova.core.recipes.crafting.ShapelessCraftingRecipe; +import nova.internal.core.Game; + +import java.util.Optional; + +/** + * @author Stan Hebben + */ +public class ShapelessRecipeOre extends ShapelessOreRecipe { + private final ShapelessCraftingRecipe recipe; + + public ShapelessRecipeOre(Object[] ingredients, ShapelessCraftingRecipe recipe) { + super((ItemStack) Game.natives().toNative(recipe.getNominalOutput().get()), ingredients); + + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + Optional craftingResult = recipe.getCraftingResult(MCCraftingGrid.get(inventory)); + if (craftingResult.isPresent()) { + return ((ItemStack) Game.natives().toNative(craftingResult.get())).copy(); + } + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/NovaFolderResourcePack.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/NovaFolderResourcePack.java new file mode 100644 index 000000000..08c06cae6 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/NovaFolderResourcePack.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.render; + +import com.google.common.base.Charsets; +import net.minecraft.client.resources.FolderResourcePack; +import net.minecraft.util.ResourceLocation; +import nova.core.wrapper.mc.forge.v1_11.NovaMinecraftPreloader; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class NovaFolderResourcePack extends FolderResourcePack { + private final String modid; + private final String[] domains; + + public NovaFolderResourcePack(File file, String modid, String[] domains) { + super(file); + this.modid = modid; + this.domains = domains; + } + + @Override + public Set getResourceDomains() { + Set domains = new HashSet<>(); + domains.add(modid); + domains.addAll(Arrays.asList(this.domains)); + return domains; + } + + private String transform(String path) { + return path; + } + + @Override + protected InputStream getInputStreamByName(String path) throws IOException { + try { + return new BufferedInputStream(new FileInputStream(new File(this.resourcePackFile, transform(path)))); + } catch (IOException e) { + if (path.endsWith("sounds.json")) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generateSoundJSON(this).getBytes(Charsets.UTF_8)); + } else if (path.equals("pack.mcmeta")) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generatePackMcmeta().getBytes(Charsets.UTF_8)); + } else { + if (path.endsWith(".mcmeta")) { + return new ByteArrayInputStream("{}".getBytes()); + } + throw e; + } + } + } + + @Override + public boolean hasResourceName(String path) { + return super.hasResourceName(transform(path)); + } + + @Override + public boolean resourceExists(ResourceLocation rl) { + //Hack Sounds + if (rl.getResourcePath().endsWith("sounds.json") || rl.getResourcePath().endsWith("pack.mcmeta")) { + return true; + } + + return new File(resourcePackFile, "assets/" + rl.getResourceDomain() + "/" + rl.getResourcePath()).isFile() || new File(resourcePackFile, rl.getResourceDomain() + "/" + rl.getResourcePath().replace(".mcmeta", "")).isFile(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/NovaResourcePack.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/NovaResourcePack.java new file mode 100644 index 000000000..504e4559f --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/NovaResourcePack.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.render; + +import com.google.common.base.Charsets; +import net.minecraft.client.resources.FileResourcePack; +import net.minecraft.util.ResourceLocation; +import nova.core.wrapper.mc.forge.v1_11.NovaMinecraftPreloader; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class NovaResourcePack extends FileResourcePack { + private final String modid; + private final String[] domains; + + public NovaResourcePack(File file, String modid, String[] domains) { + super(file); + this.modid = modid; + this.domains = domains; + } + + @Override + public Set getResourceDomains() { + HashSet domains = new HashSet<>(); + domains.add(modid); + domains.addAll(Arrays.asList(this.domains)); + return domains; + } + + private String transform(String path) { + return path.replaceFirst("assets[/\\\\]minecraft", modid); + } + + @Override + protected InputStream getInputStreamByName(String path) throws IOException { + try { + return super.getInputStreamByName(transform(path)); + } catch (IOException e) { + if (path.endsWith("sounds.json")) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generateSoundJSON(this).getBytes(Charsets.UTF_8)); + } else if (path.equals("pack.mcmeta")) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generatePackMcmeta().getBytes(Charsets.UTF_8)); + } else { + if (path.endsWith(".mcmeta")) { + return new ByteArrayInputStream("{}".getBytes()); + } + throw e; + } + } + } + + @Override + public boolean hasResourceName(String path) { + return super.hasResourceName(transform(path)); + } + + @Override + public boolean resourceExists(ResourceLocation rl) { + //Hack Sounds and McMeta + if (rl.getResourcePath().endsWith("sounds.json") || rl.getResourcePath().endsWith("pack.mcmeta")) { + return true; + } + + return super.resourceExists(rl); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/RenderUtility.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/RenderUtility.java new file mode 100644 index 000000000..0c3d52672 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/render/RenderUtility.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.render; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.block.model.FaceBakery; +import net.minecraft.client.renderer.block.model.ItemModelGenerator; +import net.minecraft.client.renderer.block.model.ModelBlock; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.resources.IResource; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.ModelBakeEvent; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nova.core.component.renderer.Renderer; +import nova.core.component.renderer.StaticRenderer; +import nova.core.render.texture.BlockTexture; +import nova.core.render.texture.ItemTexture; +import nova.core.render.texture.Texture; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward.FWItem; +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.forward.FWEmptyModel; +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.forward.FWSmartBlockModel; +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.forward.FWSmartItemModel; +import nova.internal.core.Game; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Optional; + +import static org.lwjgl.opengl.GL11.GL_BLEND; +import static org.lwjgl.opengl.GL11.GL_FLAT; +import static org.lwjgl.opengl.GL11.GL_LINE_SMOOTH; +import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA; +import static org.lwjgl.opengl.GL11.GL_POLYGON_SMOOTH; +import static org.lwjgl.opengl.GL11.GL_SMOOTH; +import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA; +import static org.lwjgl.opengl.GL11.glBlendFunc; +import static org.lwjgl.opengl.GL11.glDisable; +import static org.lwjgl.opengl.GL11.glEnable; +import static org.lwjgl.opengl.GL11.glShadeModel; + +/** + * @author Calclavia + */ +@SideOnly(Side.CLIENT) +public class RenderUtility { + + public static final ResourceLocation particleResource = new ResourceLocation("textures/particle/particles.png"); + + public static final RenderUtility instance = new RenderUtility(); + // Cruft needed to generate default item models + protected static final ItemModelGenerator ITEM_MODEL_GENERATOR = new ItemModelGenerator(); + protected static final FaceBakery FACE_BAKERY = new FaceBakery(); + // Ugly D: + protected static final ModelBlock MODEL_GENERATED = ModelBlock.deserialize( + "{" + + " \"elements\":[{\n" + + " \"from\": [0, 0, 0],\n" + + " \"to\": [16, 16, 16],\n" + + " \"faces\": {\n" + + " \"down\": {\"uv\": [0, 0, 16, 16], \"texture\":\"\"}\n" + + " }\n" + + " }],\n" + + " \"display\": {\n" + + " \"thirdperson_righthand\": {\n" + + " \"rotation\": [ -90, 0, 0 ],\n" + + " \"translation\": [ 0, 1, -3 ],\n" + + " \"scale\": [ 0.55, 0.55, 0.55 ]\n" + + " },\n" + + " \"firstperson_righthand\": {\n" + + " \"rotation\": [ 0, -90, 25 ],\n" + + " \"translation\": [ 0, 3.75, 2.3125 ],\n" + + " \"scale\": [ 0.6, 0.6, 0.6 ]\n" + + " },\n" + + " \"firstperson_lefthand\": {\n" + + " \"rotation\": [ 0, 90, -25 ],\n" + + " \"translation\": [ 0, 3.75, 2.3125 ],\n" + + " \"scale\": [ 0.6, 0.6, 0.6 ]\n" + + " }\n" + + " }\n" + + "}"); + //NOVA Texture to MC TextureAtlasSprite + private final HashMap textureMap = new HashMap<>(); + + /** + * Enables blending. + */ + public static void enableBlending() { + glShadeModel(GL_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + /** + * Disables blending. + */ + public static void disableBlending() { + glShadeModel(GL_FLAT); + glDisable(GL_LINE_SMOOTH); + glDisable(GL_POLYGON_SMOOTH); + glDisable(GL_BLEND); + } + + public static void enableLighting() { + RenderHelper.enableStandardItemLighting(); + } + + /** + * Disables lighting and turns glow on. + */ + public static void disableLighting() { + RenderHelper.disableStandardItemLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240.0F, 240.0F); + } + + public static void disableLightmap() { + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + glDisable(GL11.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + } + + public static void enableLightmap() { + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + glEnable(GL11.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + } + + public TextureAtlasSprite getTexture(Optional texture) { + if (!texture.isPresent()) + return Minecraft.getMinecraft().getTextureMapBlocks().getMissingSprite(); + return getTexture(texture.get()); + } + + public TextureAtlasSprite getTexture(Texture texture) { + if (textureMap.containsKey(texture)) { + return textureMap.get(texture); + } + + //Fallback to MC texture + return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(texture.domain + ":" + texture.getPath().replaceFirst("textures/", "").replace(".png", "")); + } + + /** + * Handles NOVA texture registration. + * @param event Event + */ + @SubscribeEvent + public void preTextureHook(TextureStitchEvent.Pre event) { + if (event.getMap() == Minecraft.getMinecraft().getTextureMapBlocks()) { + Game.render().blockTextures.forEach(t -> registerIcon(t, event)); + Game.render().itemTextures.forEach(t -> registerIcon(t, event)); + //TODO: This is HACKS. We should create custom sprite sheets for entities. + Game.render().entityTextures.forEach(t -> registerIcon(t, event)); + } + } + + public void registerIcon(Texture texture, TextureStitchEvent.Pre event) { + String resPath = (texture instanceof BlockTexture ? "blocks" : texture instanceof ItemTexture ? "items" : "entities") + "/" + texture.resource; + System.out.println(texture + " (" + texture.domain + ':' + resPath + ')'); + TextureAtlasSprite sprite = event.getMap().registerSprite(new ResourceLocation(texture.domain, resPath)); + textureMap.put(texture, sprite); + System.out.println(sprite); + } + + @SubscribeEvent + public void onModelBakeEvent(ModelBakeEvent event) { + //Register all blocks + Game.blocks().registry.forEach(blockFactory -> { + Object blockObj = Game.natives().toNative(blockFactory.build()); + if (blockObj instanceof FWBlock) { + FWBlock block = (FWBlock) blockObj; + ResourceLocation blockRL = net.minecraft.block.Block.REGISTRY.getNameForObject(block); + Item itemFromBlock = Item.getItemFromBlock(block); + ResourceLocation itemRL = Item.REGISTRY.getNameForObject(itemFromBlock); + ModelResourceLocation blockLocation = new ModelResourceLocation(blockRL, "normal"); + ModelResourceLocation itemLocation = new ModelResourceLocation(itemRL, "inventory"); + if (block.dummy.components.has(StaticRenderer.class)) { + event.getModelRegistry().putObject(blockLocation, new FWSmartBlockModel(block.dummy, true)); + } else { + event.getModelRegistry().putObject(blockLocation, new FWEmptyModel()); + } + event.getModelRegistry().putObject(itemLocation, new FWSmartBlockModel(block.dummy, true)); + } + }); + + //Register all items + Game.items().registry.forEach(itemFactory -> { + Object stackObj = Game.natives().toNative(itemFactory.build()); + if (stackObj instanceof ItemStack) { + Item itemObj = ((ItemStack) stackObj).getItem(); + if (itemObj instanceof FWItem) { + FWItem item = (FWItem) itemObj; + ResourceLocation objRL = Item.REGISTRY.getNameForObject(item); + ModelResourceLocation itemLocation = new ModelResourceLocation(objRL, "inventory"); + + nova.core.item.Item dummy = item.getItemFactory().build(); + + if (dummy.components.has(Renderer.class)) { + event.getModelRegistry().putObject(itemLocation, new FWSmartItemModel(dummy)); + } + } + } + }); + } + + public void preInit() { + //Load models + Game.render().modelProviders.forEach(m -> { + ResourceLocation resource = new ResourceLocation(m.domain, "models/" + m.name + "." + m.getType()); + try { + IResource res = Minecraft.getMinecraft().getResourceManager().getResource(resource); + m.load(res.getInputStream()); + } catch (IOException e) { + throw new RuntimeException("IO Exception reading model format", e); + } + }); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/MCInputManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/MCInputManager.java new file mode 100644 index 000000000..aecf19e06 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/MCInputManager.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.util; + +import nova.core.game.InputManager; +import org.lwjgl.input.Keyboard; + +/** + * The MC KeyManager + * @author Calclavia + */ +// TODO: Does not work yet. Need a full map between the input and LWGL input. +public class MCInputManager extends InputManager { + + @Override + public void mapKeys() { + // Map jlwgl input to NOVA Keys, slightly hacky but functional. + for (Key key : Key.values()) { + try { + keys.put(Keyboard.class.getDeclaredField(key.name()).getInt(null), key); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public boolean isKeyDown(Key key) { + // TODO: Sync this withPriority server side for server-side events. Need a packet manager + return Keyboard.isKeyDown(getNativeKeyCode(key)); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/MCLanguageManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/MCLanguageManager.java new file mode 100644 index 000000000..5b7ad087b --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/MCLanguageManager.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.util; + +import net.minecraft.util.text.translation.I18n; +import net.minecraftforge.fml.common.FMLCommonHandler; +import nova.core.util.registry.LanguageManager; +import nova.internal.core.Game; + +/** + * @deprecated Removed in Forge 1.9 + * + * @author Calclavia + */ +@Deprecated +public class MCLanguageManager extends LanguageManager { + + @Override + public void register(String language, String key, String value) { +// LanguageRegistry.instance().addStringLocalization(key, language, value); + } + + @Override + public String getCurrentLanguage() { + return FMLCommonHandler.instance().getCurrentLanguage(); + } + + @Override + public String translate(String key) { + return I18n.translateToLocal(key); + } + + @Override + public void init() { + Game.events().publish(new Init(this)); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ModCreativeTab.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ModCreativeTab.java new file mode 100644 index 000000000..34cfd2a74 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ModCreativeTab.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.util; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +/** + * @author Calclavia + */ +public class ModCreativeTab extends CreativeTabs { + public ItemStack item; + + public ModCreativeTab(String label, Item item) { + super(label); + + this.item = new ItemStack(item); + } + + public ModCreativeTab(String label, ItemStack item) { + super(label); + + this.item = item; + } + + public ModCreativeTab(String label) { + this(label, ItemStack.EMPTY); + } + + @Override + public ItemStack getTabIconItem() { + return item; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ObfuscationConstants.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ObfuscationConstants.java new file mode 100644 index 000000000..fe6303417 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ObfuscationConstants.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.util; + +/** + * @author Stan Hebben + */ +public class ObfuscationConstants { + public static final String[] NBTTAGLIST_TAGLIST = { "tagList", "field_74747_a" }; + public static final String[] OREDICTIONARY_IDTOSTACK = { "idToStack" }; + public static final String[] OREDICTIONARY_IDTOSTACKUN = { "idToStackUn" }; + public static final String[] MINECRAFTSERVER_ANVILFILE = { "anvilFile", "field_71308_o" }; + public static final String[] INVENTORYCRAFTING_EVENTHANDLER = { "eventHandler", "field_70465_c" }; + public static final String[] SLOTCRAFTING_PLAYER = { "thePlayer", "field_75238_b" }; + public static final String[] STRINGTRANSLATE_INSTANCE = { "instance", "field_74817_a" }; + public static final String[] CRAFTINGMANAGER_RECIPES = { "recipes", "field_77597_b" }; + + private ObfuscationConstants() { + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ReflectionUtil.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ReflectionUtil.java new file mode 100644 index 000000000..b355784d4 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/ReflectionUtil.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.util; + +import com.google.common.collect.BiMap; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.SlotCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.WeightedRandom; +import net.minecraft.util.text.translation.I18n; +import net.minecraft.util.text.translation.LanguageMap; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.fml.common.registry.EntityRegistry; +import net.minecraftforge.oredict.OreDictionary; +import net.minecraftforge.oredict.ShapedOreRecipe; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Common class for all runtime hacks (stuff requiring reflection). It is not + * unexpected to have it break withPriority new minecraft versions and may need regular + * adjustment - as such, those have been collected here. + * @author Stan Hebben + */ +public class ReflectionUtil { + private static final Field NBTTAGLIST_TAGLIST; + private static final Field OREDICTIONARY_IDTOSTACK; + private static final Field OREDICTIONARY_IDTOSTACKUN; + private static final Field MINECRAFTSERVER_ANVILFILE; + private static final Field SHAPEDORERECIPE_WIDTH; + private static final Field INVENTORYCRAFTING_EVENTHANDLER; + private static final Field SLOTCRAFTING_PLAYER; + + private static final Field ENTITYREGISTRY_CLASSREGISTRATIONS; + private static final Field SEEDENTRY_SEED; + private static final Constructor SEEDENTRY_CONSTRUCTOR; + + static { + NBTTAGLIST_TAGLIST = getField(NBTTagList.class, ObfuscationConstants.NBTTAGLIST_TAGLIST); + OREDICTIONARY_IDTOSTACK = getField(OreDictionary.class, ObfuscationConstants.OREDICTIONARY_IDTOSTACK); + OREDICTIONARY_IDTOSTACKUN = getField(OreDictionary.class, ObfuscationConstants.OREDICTIONARY_IDTOSTACKUN); + MINECRAFTSERVER_ANVILFILE = getField(MinecraftServer.class, ObfuscationConstants.MINECRAFTSERVER_ANVILFILE); + SHAPEDORERECIPE_WIDTH = getField(ShapedOreRecipe.class, new String[] { "width" }); + INVENTORYCRAFTING_EVENTHANDLER = getField(InventoryCrafting.class, ObfuscationConstants.INVENTORYCRAFTING_EVENTHANDLER); + SLOTCRAFTING_PLAYER = getField(SlotCrafting.class, ObfuscationConstants.SLOTCRAFTING_PLAYER); + + ENTITYREGISTRY_CLASSREGISTRATIONS = getField(EntityRegistry.class, new String[] { "entityClassRegistrations" }); + + Class forgeSeedEntry = null; + try { + forgeSeedEntry = (Class) Class.forName("net.minecraftforge.common.ForgeHooks$SeedEntry"); + } catch (ClassNotFoundException ex) { + } + + SEEDENTRY_SEED = getField(forgeSeedEntry, "seed"); + + Constructor seedEntryConstructor = null; + + try { + seedEntryConstructor = forgeSeedEntry.getConstructor(ItemStack.class, int.class); + seedEntryConstructor.setAccessible(true); + } catch (NoSuchMethodException | SecurityException ex) { + Logger.getLogger(ReflectionUtil.class.getName()).log(Level.SEVERE, null, ex); + } + + SEEDENTRY_CONSTRUCTOR = seedEntryConstructor; + } + + private ReflectionUtil() { + } + + public static BiMap, EntityRegistry.EntityRegistration> getEntityClassRegistrations() { + try { + return (BiMap, EntityRegistry.EntityRegistration>) ENTITYREGISTRY_CLASSREGISTRATIONS.get(EntityRegistry.instance()); + } catch (IllegalArgumentException | IllegalAccessException ex) { + return null; + } + } + + public static List getTagList(NBTTagList list) { + if (NBTTAGLIST_TAGLIST == null) { + return null; + } + try { + return (List) NBTTAGLIST_TAGLIST.get(list); + } catch (IllegalArgumentException | IllegalAccessException ex) { + return null; + } + } + + public static List getSeeds() { + return getPrivateStaticObject(ForgeHooks.class, "seedList"); + } + + /** + * @return {@link Collections#emptyMap()} + * @deprecated Removed in Forge 1.9 + */ + @Deprecated + public static Map getChestLoot() { + return Collections.emptyMap();//getPrivateStaticObject(ChestGenHooks.class, "chestInfo"); + } + + public static Map getTranslations() { + return getPrivateObject( + getPrivateStaticObject(I18n.class, "localizedName", "field_74839_a"), + "languageList", + "field_74816_c"); + } + + public static List> getOreIdStacks() { + try { + return (List>) OREDICTIONARY_IDTOSTACK.get(null); + } catch (IllegalAccessException ex) { + logError("ERROR - could not load ore dictionary stacks!"); + return null; + } + } + + public static List> getOreIdStacksUn() { + try { + return (List>) OREDICTIONARY_IDTOSTACKUN.get(null); + } catch (IllegalAccessException ex) { + logError("ERROR - could not load ore dictionary stacks!"); + return null; + } + } + + public static File getAnvilFile(MinecraftServer server) { + try { + return (File) MINECRAFTSERVER_ANVILFILE.get(server); + } catch (IllegalAccessException ex) { + logError("could not load anvil file!"); + return null; + } + } + + public static File getWorldDirectory(MinecraftServer server) { + if (server.isDedicatedServer()) { + return server.getFile("world"); + } else { + File worldsDir = getAnvilFile(server); + if (worldsDir == null) { + return null; + } + + return new File(worldsDir, server.getFolderName()); + } + } + + public static int getShapedOreRecipeWidth(ShapedOreRecipe recipe) { + try { + return SHAPEDORERECIPE_WIDTH.getInt(recipe); + } catch (IllegalAccessException ex) { + logError("could not load shaped ore recipe width!"); + return 3; + } + } + + public static Container getCraftingContainer(InventoryCrafting inventory) { + try { + return (Container) INVENTORYCRAFTING_EVENTHANDLER.get(inventory); + } catch (IllegalAccessException ex) { + logError("could not get inventory eventhandler"); + return null; + } + } + + public static EntityPlayer getCraftingSlotPlayer(SlotCrafting slot) { + try { + return (EntityPlayer) SLOTCRAFTING_PLAYER.get(slot); + } catch (IllegalAccessException | NullPointerException ex) { + logError("could not get inventory eventhandler"); + return null; + } + } + + public static LanguageMap getStringTranslateInstance() { + try { + Field field = getField(LanguageMap.class, ObfuscationConstants.STRINGTRANSLATE_INSTANCE); + return (LanguageMap) field.get(null); + } catch (IllegalAccessException ex) { + logError("could not get string translator"); + return null; + } + } + + public static ItemStack getSeedEntrySeed(Object entry) { + try { + return (ItemStack) SEEDENTRY_SEED.get(entry); + } catch (IllegalAccessException ex) { + logError("could not get SeedEntry seed"); + return null; + } + } + + public static void setCraftingRecipeList(List craftingRecipeList) { + if (!setPrivateObject( + CraftingManager.getInstance(), + craftingRecipeList, + ObfuscationConstants.CRAFTINGMANAGER_RECIPES)) { + logError("could not set crafting recipe list"); + } + } + + /*public static WeightedRandom.Item constructSeedEntry(WeightedItemStack stack) { + try { + return SEEDENTRY_CONSTRUCTOR.newInstance(MineTweakerMC.getItemStack(stack.getStack()), (int) stack.getChance()); + } catch (InstantiationException ex) { + logError("could not construct SeedEntry"); + } catch (IllegalAccessException ex) { + logError("could not construct SeedEntry"); + } catch (IllegalArgumentException ex) { + logError("could not construct SeedEntry"); + } catch (InvocationTargetException ex) { + logError("could not construct SeedEntry"); + } + + return null; + }*/ + + public static T getPrivateStaticObject(Class cls, String... names) { + for (String name : names) { + try { + Field field = cls.getDeclaredField(name); + field.setAccessible(true); + return (T) field.get(null); + } catch (NoSuchFieldException | SecurityException | IllegalAccessException ex) { + + } + } + + return null; + } + + public static T getPrivateObject(Object object, String... names) { + Class cls = object.getClass(); + for (String name : names) { + try { + Field field = cls.getDeclaredField(name); + field.setAccessible(true); + return (T) field.get(object); + } catch (Exception ex) { + + } + } + + return null; + } + + public static boolean setPrivateObject(Object object, Object value, String... names) { + Class cls = object.getClass(); + for (String name : names) { + try { + Field field = cls.getDeclaredField(name); + field.setAccessible(true); + field.set(object, value); + return true; + } catch (Exception ex) { + + } + } + + return false; + } + + // ####################### + // ### Private Methods ### + // ####################### + + private static Field getField(Class cls, String... names) { + for (String name : names) { + try { + Field field = cls.getDeclaredField(name); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException | SecurityException ex) { + } + } + + return null; + } + + private static void logError(String message) { + System.out.println("ERROR: " + message); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/WrapUtility.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/WrapUtility.java new file mode 100644 index 000000000..26b530a73 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/WrapUtility.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.util; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import nova.core.entity.Entity; +import nova.core.entity.component.Player; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward.BWEntity; +import nova.internal.core.Game; + +import java.util.Objects; +import java.util.Optional; + +/** + * Wrap utility methods. + * @author Calclavia + */ +public class WrapUtility { + + public static Optional getNovaPlayer(EntityPlayer player) { + return ((Entity)Game.natives().toNova(player)).components.getOp(Player.class); + } + + public static String getItemID(Item item, int meta) { + if (item.getHasSubtypes()) { + return Item.REGISTRY.getNameForObject(item) + ":" + meta; + } else { + return Objects.toString(Item.REGISTRY.getNameForObject(item)); + } + } + + public static EntityPlayer getMCPlayer(Optional player) { + if (!player.isPresent()) + return null; + + Entity entity = player.get().entity(); + if (entity instanceof BWEntity) { + if (((BWEntity)entity).entity instanceof EntityPlayer) + return (EntityPlayer)((BWEntity)entity).entity; + } + + // TODO + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/WrapperEvent.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/WrapperEvent.java new file mode 100644 index 000000000..7f2feedac --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/util/WrapperEvent.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.util; + +import net.minecraft.item.ItemStack; +import nova.core.block.Block; +import nova.core.entity.Entity; +import nova.core.event.BlockEvent; +import nova.core.event.bus.CancelableEvent; +import nova.core.event.bus.Event; +import nova.core.item.Item; +import nova.core.util.Direction; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11.wrapper.capability.forward.FWCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.backward.BWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward.BWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.backward.BWItem; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Optional; + +/** + * Events for wrappers to hook into + * @author Calclavia + */ +public class WrapperEvent { + + public static class RedstoneConnect extends BlockEvent { + public final Direction direction; + public boolean canConnect; + + public RedstoneConnect(World world, Vector3D position, Direction direction) { + super(world, position); + this.direction = direction; + } + } + + public static class StrongRedstone extends BlockEvent { + public final Direction direction; + public int power; + + public StrongRedstone(World world, Vector3D position, Direction direction) { + super(world, position); + this.direction = direction; + } + } + + public static class WeakRedstone extends BlockEvent { + public final Direction direction; + public int power; + + public WeakRedstone(World world, Vector3D position, Direction direction) { + super(world, position); + this.direction = direction; + } + } + + public static class BWBlockCreate extends BlockEvent { + public final net.minecraft.block.Block mcBlock; + public final BWBlock novaBlock; + + public BWBlockCreate(World world, Vector3D position, BWBlock novaBlock, net.minecraft.block.Block mcBlock) { + super(world, position); + this.novaBlock = novaBlock; + this.mcBlock = mcBlock; + } + } + + public static class BWItemCreate extends CancelableEvent { + public final net.minecraft.item.Item mcItem; + public final BWItem novaItem; + public final Optional itemStack; + + public BWItemCreate(BWItem novaItem, net.minecraft.item.Item mcItem) { + this.novaItem = novaItem; + this.mcItem = mcItem; + this.itemStack = Optional.empty(); + } + + public BWItemCreate(BWItem novaItem, net.minecraft.item.Item mcItem, ItemStack itemStack) { + this.novaItem = novaItem; + this.mcItem = mcItem; + this.itemStack = Optional.of(itemStack); + } + } + + public static class BWEntityCreate extends CancelableEvent { + public final net.minecraft.entity.Entity mcEntity; + public final BWEntity novaEntity; + + public BWEntityCreate(BWEntity novaEntity, net.minecraft.entity.Entity mcEntity) { + this.novaEntity = novaEntity; + this.mcEntity = mcEntity; + } + } + + public static class FWItemInitCapabilities extends Event { + public final Item novaItem; + public final FWCapabilityProvider capabilityProvider; + + public FWItemInitCapabilities(Item novaItem, FWCapabilityProvider capabilityProvider) { + this.novaItem = novaItem; + this.capabilityProvider = capabilityProvider; + } + } + + public static class FWTileCreate extends Event { + public final Block novaBlock; + public final FWTile tileEntity; + + public FWTileCreate(Block novaBlock, FWTile tileEntity) { + this.novaBlock = novaBlock; + this.tileEntity = tileEntity; + } + } + + public static class FWEntityCreate extends Event { + public final Entity novaEntity; + public final FWEntity mcEntity; + + public FWEntityCreate(Entity novaEntity, FWEntity mcEntity) { + this.novaEntity = novaEntity; + this.mcEntity = mcEntity; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/DirectionConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/DirectionConverter.java new file mode 100644 index 000000000..334bdbcdd --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/DirectionConverter.java @@ -0,0 +1,53 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package nova.core.wrapper.mc.forge.v1_11.wrapper; + +import net.minecraft.util.EnumFacing; +import nova.core.nativewrapper.NativeConverter; +import nova.core.util.Direction; + +/** + * + * @author ExE Boss + */ +public class DirectionConverter implements NativeConverter { + + @Override + public Class getNovaSide() { + return Direction.class; + } + + @Override + public Class getNativeSide() { + return EnumFacing.class; + } + + @Override + public Direction toNova(EnumFacing nativeObj) { + switch (nativeObj) { + case DOWN: return Direction.DOWN; + case UP: return Direction.UP; + case NORTH: return Direction.NORTH; + case SOUTH: return Direction.SOUTH; + case WEST: return Direction.WEST; + case EAST: return Direction.EAST; + default: return Direction.UNKNOWN; + } + } + + @Override + public EnumFacing toNative(Direction novaObj) { + switch (novaObj) { + case DOWN: return EnumFacing.DOWN; + case UP: return EnumFacing.UP; + case NORTH: return EnumFacing.NORTH; + case SOUTH: return EnumFacing.SOUTH; + case WEST: return EnumFacing.WEST; + case EAST: return EnumFacing.EAST; + default: return (EnumFacing) null; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/VectorConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/VectorConverter.java new file mode 100644 index 000000000..8bc1b9487 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/VectorConverter.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper; + +import net.minecraft.util.math.BlockPos; +import nova.core.nativewrapper.NativeConverter; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +public class VectorConverter implements NativeConverter { + @Override + public Class getNovaSide() { + return Vector3D.class; + } + + @Override + public Class getNativeSide() { + return BlockPos.class; + } + + @Override + public Vector3D toNova(BlockPos pos) { + return new Vector3D(pos.getX(), pos.getY(), pos.getZ()); + } + + @Override + public BlockPos toNative(Vector3D vec) { + return new BlockPos(vec.getX(), vec.getY(), vec.getZ()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/BlockConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/BlockConverter.java new file mode 100644 index 000000000..7c8442567 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/BlockConverter.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.registry.GameRegistry; +import nova.core.block.Block; +import nova.core.block.BlockFactory; +import nova.core.block.BlockManager; +import nova.core.component.Category; +import nova.core.event.BlockEvent; +import nova.core.loader.Loadable; +import nova.core.nativewrapper.NativeConverter; +import nova.core.wrapper.mc.forge.v1_11.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11.util.ModCreativeTab; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.backward.BWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward.FWItemBlock; +import nova.internal.core.Game; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Optional; + +/** + * @author Calclavia + */ +//TODO: Should be +public class BlockConverter implements NativeConverter, Loadable { + /** + * A map of all blockFactory to MC blocks registered + */ + public final HashMap blockFactoryMap = new HashMap<>(); + + public static BlockConverter instance() { + return (BlockConverter) Game.natives().getNative(Block.class, net.minecraft.block.Block.class); + } + + @Override + public Class getNovaSide() { + return Block.class; + } + + @Override + public Class getNativeSide() { + return net.minecraft.block.Block.class; + } + + @Override + public Block toNova(net.minecraft.block.Block nativeBlock) { + //Prevent recursive wrapping + if (nativeBlock instanceof FWBlock) { + return ((FWBlock) nativeBlock).dummy; + } + + if (nativeBlock == Blocks.AIR) { + return Game.blocks().getAirBlock().build(); + } + + return new BWBlock(nativeBlock); + } + + @Override + public net.minecraft.block.Block toNative(Block novaBlock) { + //Prevent recursive wrapping + if (novaBlock instanceof BWBlock) { + return ((BWBlock) novaBlock).mcBlock; + } + + return toNative(novaBlock.getFactory()); + } + + public net.minecraft.block.Block toNative(BlockFactory blockFactory) { + return blockFactoryMap.get(blockFactory); + } + + /** + * Register all Nova blocks + */ + @Override + public void preInit() { + registerMinecraftToNOVA(); + registerNOVAToMinecraft(); + } + + private void registerMinecraftToNOVA() { + //TODO: Will this register ALL Forge mod blocks as well? + BlockManager blockManager = Game.blocks(); + net.minecraft.block.Block.REGISTRY.forEach(obj -> + blockManager.register( + new BlockFactory(net.minecraft.block.Block.REGISTRY.getNameForObject(obj).toString(), + () -> new BWBlock((net.minecraft.block.Block) obj), evt -> { + }) + ) + ); + } + + private void registerNOVAToMinecraft() { + BlockManager blockManager = Game.blocks(); + + //Register air block + BlockFactory airBlock = new BlockFactory("air", () -> new BWBlock(Blocks.AIR) { + @Override + public boolean canReplace() { + return true; + } + }, evt -> { + }); + + blockManager.register(airBlock); + + //NOTE: There should NEVER be blocks already registered in preInit() stage of a NativeConverter. + Game.events().on(BlockEvent.Register.class).bind(evt -> registerNovaBlock(evt.blockFactory)); + } + + private void registerNovaBlock(BlockFactory blockFactory) { + FWBlock blockWrapper = new FWBlock(blockFactory); + FWItemBlock itemBlockWrapper = new FWItemBlock(blockWrapper); + blockFactoryMap.put(blockFactory, blockWrapper); + String blockId = blockFactory.getID(); // TODO? + ResourceLocation id = new ResourceLocation(blockId); + GameRegistry.register(blockWrapper, id); + GameRegistry.register(itemBlockWrapper, id); + NovaMinecraft.proxy.postRegisterBlock(blockWrapper); + + if (blockWrapper.dummy.components.has(Category.class) && FMLCommonHandler.instance().getSide().isClient()) { + //Add into creative tab + Category category = blockWrapper.dummy.components.get(Category.class); + Optional first = Arrays.stream(CreativeTabs.CREATIVE_TAB_ARRAY) + .filter(tab -> tab.getTabLabel().equals(category.name)) + .findFirst(); + if (first.isPresent()) { + blockWrapper.setCreativeTab(first.get()); + } else { + Optional item = category.item; + ModCreativeTab tab = new ModCreativeTab(category.name, item.isPresent() ? Game.natives().toNative(item.get()) : Item.getItemFromBlock(blockWrapper)); + blockWrapper.setCreativeTab(tab); + } + } + + System.out.println("[NOVA]: Registered '" + blockFactory.getID() + "' block."); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/backward/BWBlock.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/backward/BWBlock.java new file mode 100644 index 000000000..07633a8fa --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/backward/BWBlock.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.backward; + +import net.minecraft.block.BlockSnow; +import net.minecraft.block.SoundType; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import nova.core.block.Block; +import nova.core.block.component.BlockProperty; +import nova.core.block.component.LightEmitter; +import nova.core.component.misc.Collider; +import nova.core.component.transform.BlockTransform; +import nova.core.item.ItemFactory; +import nova.core.retention.Data; +import nova.core.retention.Storable; +import nova.core.retention.Store; +import nova.core.sound.Sound; +import nova.core.util.shape.Cuboid; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.world.BWWorld; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class BWBlock extends Block implements Storable { + public final net.minecraft.block.Block mcBlock; + @Store + public int metadata; + private TileEntity mcTileEntity; + + public BWBlock(net.minecraft.block.Block block) { + this.mcBlock = block; + } + + public BWBlock(net.minecraft.block.Block block, World world, Vector3D pos) { + this.mcBlock = block; + + BlockTransform transform = components.add(new BlockTransform()); + transform.setWorld(world); + transform.setPosition(pos); + + components.add(new BlockProperty.Opacity().setLightTransmission(!blockState().getMaterial().blocksLight())); + + BlockProperty.BlockSound blockSound = components.add(new BlockProperty.BlockSound()); + SoundType soundType; + if (getMcBlockAccess() instanceof net.minecraft.world.World) + soundType = mcBlock.getSoundType(blockState(), (net.minecraft.world.World)getMcBlockAccess(), new BlockPos(x(), y(), z()), null); + else + soundType = mcBlock.getSoundType(); + + blockSound.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.PLACE, + new Sound(soundType.getPlaceSound().getSoundName().getResourceDomain(), + soundType.getPlaceSound().getSoundName().getResourcePath())); + + blockSound.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.BREAK, + new Sound(soundType.getBreakSound().getSoundName().getResourceDomain(), + soundType.getBreakSound().getSoundName().getResourcePath())); + + blockSound.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.WALK, + new Sound(soundType.getStepSound().getSoundName().getResourceDomain(), + soundType.getStepSound().getSoundName().getResourcePath())); + + components.add(new LightEmitter()).setEmittedLevel(() -> blockState().getLightValue(getMcBlockAccess(), new BlockPos(x(), y(), z())) / 15.0F); + components.add(new Collider(this)) + .setBoundingBox(() -> { + AxisAlignedBB aabb = blockState().getBoundingBox(getMcBlockAccess(), new BlockPos(x(), y(), z())); + return new Cuboid(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ); + }).setOcclusionBoxes(entity -> { + List aabbs = new ArrayList<>(); + blockState().addCollisionBoxToList( + Game.natives().toNative(world()), + new BlockPos(x(), y(), z()), + Game.natives().toNative(entity.isPresent() ? entity.get().components.get(Collider.class).boundingBox.get() : Cuboid.ONE.add(pos)), + aabbs, + entity.isPresent() ? Game.natives().toNative(entity.get()) : null + ); + return aabbs.stream() + .map(aabb -> (Cuboid) Game.natives().toNova(aabb)) + .map(cuboid -> cuboid.subtract(pos)) + .collect(Collectors.toSet()); + }); + WrapperEvent.BWBlockCreate event = new WrapperEvent.BWBlockCreate(world, pos, this, mcBlock); + Game.events().publish(event); + //TODO: Set selection bounds + } + + @Override + public ItemFactory getItemFactory() { + return Game.natives().toNova(new ItemStack(Item.getItemFromBlock(mcBlock))); + } + + public IBlockAccess getMcBlockAccess() { + return ((BWWorld) world()).access; + } + + public IBlockState blockState() { + return getMcBlockAccess().getBlockState(new BlockPos(x(), y(), z())); + } + + public TileEntity getTileEntity() { + if (mcTileEntity == null && mcBlock.hasTileEntity(blockState())) { + mcTileEntity = getMcBlockAccess().getTileEntity(new BlockPos(x(), y(), z())); + } + return mcTileEntity; + } + + @Override + public boolean canReplace() { + return mcBlock.canPlaceBlockAt((net.minecraft.world.World) getMcBlockAccess(), new BlockPos(x(), y(), z())); + } + + @Override + public boolean shouldDisplacePlacement() { + if (mcBlock == Blocks.SNOW_LAYER && ((int) blockState().getValue(BlockSnow.LAYERS) < 1)) { + return false; + } + + if (mcBlock == Blocks.VINE || mcBlock == Blocks.TALLGRASS || mcBlock == Blocks.DEADBUSH || mcBlock.isReplaceable(Game.natives().toNative(world()), new BlockPos(x(), y(), z()))) { + return false; + } + return super.shouldDisplacePlacement(); + } + + @Override + public void save(Data data) { + Storable.super.save(data); + + TileEntity tileEntity = getTileEntity(); + if (tileEntity != null) { + NBTTagCompound nbt = new NBTTagCompound(); + tileEntity.writeToNBT(nbt); + data.putAll(Game.natives().toNova(nbt)); + } + } + + @Override + public void load(Data data) { + Storable.super.load(data); + + TileEntity tileEntity = getTileEntity(); + if (tileEntity != null) { + tileEntity.writeToNBT(Game.natives().toNative(data)); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/BlockPosition.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/BlockPosition.java new file mode 100644 index 000000000..57c2117a3 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/BlockPosition.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.world.World; + +/** + * @author Stan Hebben + */ +public final class BlockPosition { + private final World world; + private final int x; + private final int y; + private final int z; + + public BlockPosition(World world, int x, int y, int z) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + BlockPosition that = (BlockPosition) o; + + if (x != that.x) { + return false; + } + if (y != that.y) { + return false; + } + if (z != that.z) { + return false; + } + if (!world.equals(that.world)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = world.hashCode(); + result = 31 * result + x; + result = 31 * result + y; + result = 31 * result + z; + return result; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWBlock.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWBlock.java new file mode 100644 index 000000000..99d32ea39 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWBlock.java @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.block.SoundType; +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.Explosion; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import nova.core.block.Block; +import nova.core.block.BlockFactory; +import nova.core.block.Stateful; +import nova.core.block.component.BlockProperty; +import nova.core.block.component.LightEmitter; +import nova.core.component.Updater; +import nova.core.component.misc.Collider; +import nova.core.retention.Storable; +import nova.core.sound.Sound; +import nova.core.util.Direction; +import nova.core.util.shape.Cuboid; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * A Minecraft to Nova block wrapper + * @author Calclavia + */ +public class FWBlock extends net.minecraft.block.Block { + public final Block dummy; + /** + * Reference to the wrapper Nova block + */ + private final BlockFactory factory; + private final Class blockClass; + private Map harvestedBlocks = new HashMap<>(); + + private static Material getMcMaterial(BlockFactory factory) { + Block dummy = factory.build(); + if (dummy.components.has(BlockProperty.Opacity.class)) { + // TODO allow color selection + return new ProxyMaterial(MapColor.GRAY, dummy.components.get(BlockProperty.Opacity.class)); + } else { + return Material.PISTON; + } + } + + public FWBlock(BlockFactory factory) { + //TODO: Hack build() method + super(getMcMaterial(factory)); + this.factory = factory; + this.dummy = factory.build(); + if (dummy.components.has(BlockProperty.BlockSound.class)) { + this.blockSoundType = new FWBlockSound(dummy.components.get(BlockProperty.BlockSound.class)); + } else { + BlockProperty.BlockSound properties = dummy.components.add(new BlockProperty.BlockSound()); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.BREAK, new Sound("", SoundType.STONE.getBreakSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.PLACE, new Sound("", SoundType.STONE.getPlaceSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.WALK, new Sound("", SoundType.STONE.getStepSound().getSoundName().getResourcePath())); + this.blockSoundType = SoundType.STONE; + } + this.blockClass = dummy.getClass(); + this.setUnlocalizedName(dummy.getID()); + + // Recalculate super constructor things after loading the block properly + this.fullBlock = getDefaultState().isOpaqueCube(); + this.lightOpacity = this.fullBlock ? 255 : 0; + this.translucent = !this.fullBlock; + } + + public BlockFactory getFactory() { + return this.factory; + } + + public Block getBlockInstance(IBlockAccess access, Vector3D position) { + /** + * If this block has a TileEntity, forward the method into the Stateful + * block. Otherwise, create a new instance of the block and forward the + * methods over. + */ + if (hasTileEntity(null)) { + FWTile tileWrapper = (FWTile) access.getTileEntity(new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ())); + if (tileWrapper != null && tileWrapper.getBlock() != null) { + return tileWrapper.getBlock(); + } + + try { + throw new RuntimeException("Error: Block in TileWrapper is null for " + dummy); + } catch (Exception e) { + e.printStackTrace(); + } + } + return getBlockInstance((nova.core.world.World) Game.natives().toNova(access), position); + + } + + private Block getBlockInstance(nova.core.world.World world, Vector3D position) { + // TODO: Implement obj args + Block block = factory.build(); + block.components.add(new MCBlockTransform(block, world, position)); + return block; + } + + @Override + public void onBlockHarvested(World world, BlockPos pos, IBlockState state, EntityPlayer player) { + // HACK: called before block is destroyed by the player prior to the + // player getting the drops. Determine drops here. + // hack is needed because the player sets the block to air *before* + // getting the drops. woo good logic from mojang. + if (!player.capabilities.isCreativeMode) { + harvestedBlocks.put(new BlockPosition(world, pos.getX(), pos.getY(), pos.getZ()), getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ()))); + } + } + + @Override + public List getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { + Block blockInstance; + + // see onBlockHarvested for why the harvestedBlocks hack exists + // this method will be called exactly once after destroying the block + BlockPosition position = new BlockPosition((World) world, pos.getX(), pos.getY(), pos.getZ()); + if (harvestedBlocks.containsKey(position)) { + blockInstance = harvestedBlocks.remove(position); + } else { + blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + } + + Block.DropEvent event = new Block.DropEvent(blockInstance); + blockInstance.events.publish(event); + + return new ArrayList<>( + event.drops + .stream() + .map(item -> (ItemStack) Game.natives().toNative(item)) + .collect(Collectors.toCollection(ArrayList::new)) + ); + } + + @Override + public boolean hasTileEntity(IBlockState state) { + // A block requires a TileEntity if it stores data or if it ticks. + return Storable.class.isAssignableFrom(blockClass) || Stateful.class.isAssignableFrom(blockClass) || Updater.class.isAssignableFrom(blockClass); + } + + @Override + public TileEntity createTileEntity(World world, IBlockState state) { + return FWTileLoader.loadTile(dummy.getID()); + } + + @Override + public void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighborBlock) { + Block blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + // Minecraft does not provide the neighbor :( + Block.NeighborChangeEvent evt = new Block.NeighborChangeEvent(Optional.empty()); + blockInstance.events.publish(evt); + } + + @Override + public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { + Block blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + Block.RemoveEvent evt = new Block.RemoveEvent(Optional.of(Game.natives().toNova(player))); + blockInstance.events.publish(evt); + if (evt.result) { + return super.removedByPlayer(state, world, pos, player, willHarvest); + } + return false; + } + + @Override + public void onBlockClicked(World world, BlockPos pos, EntityPlayer player) { + Block blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + RayTraceResult mop = player.rayTrace(10, 1); + Block.LeftClickEvent evt = new Block.LeftClickEvent(Game.natives().toNova(player), Direction.fromOrdinal(mop.sideHit.ordinal()), new Vector3D(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord)); + blockInstance.events.publish(evt); + } + + @Override + public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { + Block blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + Block.RightClickEvent evt = new Block.RightClickEvent(Game.natives().toNova(player), Direction.fromOrdinal(side.ordinal()), new Vector3D(hitX, hitY, hitZ)); + blockInstance.events.publish(evt); + return evt.result; + } + + + @Override + public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) { + Block blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + blockInstance.components.getOp(Collider.class).ifPresent(collider -> blockInstance.events.publish(new Collider.CollideEvent(Game.natives().toNova(entity)))); + } + + @Override + @Deprecated + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess access, BlockPos pos) { + Block blockInstance = getBlockInstance(access, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + if (blockInstance.components.has(Collider.class)) { + Cuboid cuboid = blockInstance.components.get(Collider.class).boundingBox.get(); + return new AxisAlignedBB(cuboid.min.getX(), cuboid.min.getY(), cuboid.min.getZ(), cuboid.max.getX(), cuboid.max.getY(), cuboid.max.getZ()); + } + return super.getBoundingBox(state, access, pos); + } + + @Override + @Deprecated + public AxisAlignedBB getSelectedBoundingBox(IBlockState state, World world, BlockPos pos) { + Block blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + + if (blockInstance.components.has(Collider.class)) { + Cuboid cuboid = blockInstance.components.get(Collider.class).boundingBox.get(); + return Game.natives().toNative(cuboid.add(new Vector3D(pos.getX(), pos.getY(), pos.getZ()))); + } + return super.getSelectedBoundingBox(state, world, pos); + } + + @Override + @Deprecated + public void addCollisionBoxToList(IBlockState state, World world, BlockPos pos, AxisAlignedBB boundingBox, List list, Entity entity) { + Block blockInstance = getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + blockInstance.components.getOp(Collider.class).ifPresent( + collider -> { + Set boxes = collider.occlusionBoxes.apply(Optional.ofNullable(entity != null ? Game.natives().toNova(entity) : null)); + + list.addAll( + boxes + .stream() + .map(c -> c.add(new Vector3D(pos.getX(), pos.getY(), pos.getZ()))) + .filter(c -> c.intersects((Cuboid) Game.natives().toNova(boundingBox))) + .map(cuboid -> (AxisAlignedBB) Game.natives().toNative(cuboid)) + .collect(Collectors.toList()) + ); + } + ); + } + + @Override + @Deprecated + public boolean isOpaqueCube(IBlockState state) { + if (dummy == null) { + // Superconstructor fix. -10 style points. + return true; + } + + Optional blockCollider = dummy.components.getOp(Collider.class); + + if (blockCollider.isPresent()) { + return blockCollider.get().isOpaqueCube.get(); + } else { + return super.isOpaqueCube(state); + } + } + + @Override + public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { + Optional blockCollider = dummy.components.getOp(Collider.class); + + if (blockCollider.isPresent()) { + return blockCollider.get().isCube.get(); + } else { + return super.isNormalCube(state, world, pos); + } + } + + @Override + @Deprecated + public boolean isFullCube(IBlockState state) { + Optional blockCollider = dummy.components.getOp(Collider.class); + + if (blockCollider.isPresent()) { + return blockCollider.get().isCube.get(); + } else { + return super.isFullCube(state); + } + } + + @Override + public int getLightValue(IBlockState state, IBlockAccess access, BlockPos pos) { + Block blockInstance = getBlockInstance(access, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + Optional opEmitter = blockInstance.components.getOp(LightEmitter.class); + + if (opEmitter.isPresent()) { + return Math.round(opEmitter.get().emittedLevel.get() * 15.0F); + } else { + return 0; + } + } + + @Override + public BlockRenderLayer getBlockLayer() { + return BlockRenderLayer.CUTOUT; + } + + @Override + public boolean canConnectRedstone(IBlockState state, IBlockAccess access, BlockPos pos, EnumFacing side) { + Block blockInstance = getBlockInstance(access, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + WrapperEvent.RedstoneConnect event = new WrapperEvent.RedstoneConnect(blockInstance.world(), blockInstance.position(), Direction.fromOrdinal(side.ordinal())); + Game.events().publish(event); + return event.canConnect; + } + + @Override + @Deprecated + public int getWeakPower(IBlockState state, IBlockAccess access, BlockPos pos, EnumFacing side) { + Block blockInstance = getBlockInstance(access, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + WrapperEvent.WeakRedstone event = new WrapperEvent.WeakRedstone(blockInstance.world(), blockInstance.position(), Direction.fromOrdinal(side.ordinal())); + Game.events().publish(event); + return event.power; + } + + @Override + @Deprecated + public int getStrongPower(IBlockState state, IBlockAccess access, BlockPos pos, EnumFacing side) { + Block blockInstance = getBlockInstance(access, new Vector3D(pos.getX(), pos.getY(), pos.getZ())); + WrapperEvent.StrongRedstone event = new WrapperEvent.StrongRedstone(blockInstance.world(), blockInstance.position(), Direction.fromOrdinal(side.ordinal())); + Game.events().publish(event); + return event.power; + } + + @Override + public String getUnlocalizedName() { + return super.getUnlocalizedName().replaceFirst("tile", "block"); + } + + @Override + public float getExplosionResistance(World world, BlockPos pos, Entity exploder, Explosion explosion) { + // TODO: Maybe do something withPriority these parameters. + return (float) getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())).getResistance() * 30; + } + + @Override + @Deprecated + public float getBlockHardness(IBlockState state, World world, BlockPos pos) { + return (float) getBlockInstance(world, new Vector3D(pos.getX(), pos.getY(), pos.getZ())).getHardness() * 2; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWBlockSound.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWBlockSound.java new file mode 100644 index 000000000..aa1981bc0 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWBlockSound.java @@ -0,0 +1,67 @@ +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.block.SoundType; +import net.minecraft.init.SoundEvents; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import nova.core.block.component.BlockProperty.BlockSound; +import nova.core.sound.Sound; + +/** + * @author winsock, soniex2 + */ +public class FWBlockSound extends SoundType { + private final BlockSound blockSound; + + /** + * Construct a new FWBlockSound + * @param blockSound The BlockSound to use. + */ + public FWBlockSound(BlockSound blockSound) { + super(1f, 1f, SoundEvents.BLOCK_STONE_BREAK, SoundEvents.BLOCK_STONE_STEP, SoundEvents.BLOCK_STONE_PLACE, SoundEvents.BLOCK_STONE_HIT, SoundEvents.BLOCK_STONE_FALL); + this.blockSound = blockSound; + } + + @Override + public SoundEvent getBreakSound() { + if (blockSound.blockSoundSoundMap.containsKey(BlockSound.BlockSoundTrigger.BREAK)) { + Sound sound = blockSound.blockSoundSoundMap.get(BlockSound.BlockSoundTrigger.BREAK); + if (sound.domain.isEmpty() && !sound.name.contains(".")) { + SoundEvent event = SoundEvent.REGISTRY.getObject(new ResourceLocation("dig." + sound.name)); + return event == null ? super.getPlaceSound() : event; + } + SoundEvent event = SoundEvent.REGISTRY.getObject(new ResourceLocation(sound.getID())); + return event == null ? super.getPlaceSound() : event; + } + return super.getBreakSound(); + } + + @Override + public SoundEvent getStepSound() { + if (blockSound.blockSoundSoundMap.containsKey(BlockSound.BlockSoundTrigger.WALK)) { + Sound sound = blockSound.blockSoundSoundMap.get(BlockSound.BlockSoundTrigger.WALK); + if (sound.domain.isEmpty() && !sound.name.contains(".")) { + SoundEvent event = SoundEvent.REGISTRY.getObject(new ResourceLocation("step." + sound.name)); + return event == null ? super.getPlaceSound() : event; + } + SoundEvent event = SoundEvent.REGISTRY.getObject(new ResourceLocation(sound.getID())); + return event == null ? super.getPlaceSound() : event; + } + return super.getStepSound(); + } + + @Override + public SoundEvent getPlaceSound() { + if (blockSound.blockSoundSoundMap.containsKey(BlockSound.BlockSoundTrigger.WALK)) { + Sound sound = blockSound.blockSoundSoundMap.get(BlockSound.BlockSoundTrigger.WALK); + if (sound.domain.isEmpty()) { + SoundEvent event = SoundEvent.REGISTRY.getObject(new ResourceLocation(sound.name)); + return event == null ? super.getPlaceSound() : event; + } + SoundEvent event = SoundEvent.REGISTRY.getObject(new ResourceLocation(sound.getID())); + return event == null ? super.getPlaceSound() : event; + } + // By default MC uses the block break sound for block placement + return super.getPlaceSound(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTile.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTile.java new file mode 100644 index 000000000..74afd64b1 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTile.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.INetHandler; +import net.minecraft.network.Packet; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.INetHandlerPlayClient; +import net.minecraft.network.play.server.SPacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.common.capabilities.Capability; +import nova.core.block.Block; +import nova.core.block.Stateful; +import nova.core.network.Syncable; +import nova.core.retention.Data; +import nova.core.retention.Storable; +import nova.core.util.EnumSelector; +import nova.core.wrapper.mc.forge.v1_11.network.netty.MCNetworkManager; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * A Minecraft TileEntity to Nova block wrapper + * @author Calclavia + */ +public class FWTile extends TileEntity { + + private final Map, Object> capabilities = new HashMap<>(); + private final Map, Object>> sidedCapabilities = new HashMap<>(); + + protected String blockID; + protected Block block; + protected Data cacheData = null; + + public FWTile() { + for (EnumFacing facing : EnumFacing.VALUES) + sidedCapabilities.put(facing, new HashMap<>()); + } + + public FWTile(String blockID) { + this.blockID = blockID; + } + + public Block getBlock() { + return block; + } + + public void setBlock(Block block) { + this.block = block; + } + + @Override + public SPacketUpdateTileEntity getUpdatePacket() { + if (block instanceof Syncable) { + return new FWPacketUpdateTileEntity(((MCNetworkManager) Game.network()).toMCPacket(((MCNetworkManager) Game.network()).writePacket(0, (Syncable) block)), + this.getPos(), this.getBlockMetadata(), this.getTileData()); + } + return null; + } + + @Override + public void validate() { + super.validate(); + block.components.getOrAdd(new MCBlockTransform(block, Game.natives().toNova(getWorld()), new Vector3D(pos.getX(), pos.getY(), pos.getZ()))); + + if (cacheData != null && block instanceof Storable) { + ((Storable) block).load(cacheData); + cacheData = null; + } + + block.events.publish(new Stateful.LoadEvent()); + } + + @Override + public void invalidate() { + block.events.publish(new Stateful.UnloadEvent()); + super.invalidate(); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + + nbt.setString("novaID", blockID); + + if (block != null) { + if (block instanceof Storable) { + Data data = new Data(); + ((Storable) block).save(data); + nbt.setTag("nova", Game.natives().toNative(data)); + } + } + + return nbt; + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + + blockID = nbt.getString("novaID"); + cacheData = Game.natives().toNova(nbt.getCompoundTag("nova")); + } + + public T addCapability(Capability capability, T capabilityInstance, EnumSelector facing) { + if (facing == null || facing.allowsAll()) { + if (capabilities.containsKey(capability)) + throw new IllegalArgumentException("Already has capability " + capabilityInstance.getClass()); + + capabilities.put(capability, capabilityInstance); + } else { + facing.forEach(enumFacing -> { + Map, Object> capabilities = sidedCapabilities.get(enumFacing); + + if (capabilities.containsKey(capability)) + throw new IllegalArgumentException("Already has capability " + capabilityInstance.getClass()); + + capabilities.put(capability, capabilityInstance); + }); + } + return capabilityInstance; + } + + @Override + public boolean hasCapability(Capability capability, EnumFacing facing) { + return (facing != null ? sidedCapabilities.get(facing).containsValue(capability) : capabilities.containsValue(capability)) + || super.hasCapability(capability, facing); + } + + @Override + public T getCapability(Capability capability, EnumFacing facing) { + if (!hasCapability(capability, facing)) return null; + T capabilityInstance = (T) (facing != null ? sidedCapabilities.get(facing).get(capability) : capabilities.get(capability)); + return capabilityInstance != null ? capabilityInstance : super.getCapability(capability, facing); + } + + @Override + public void setPos(BlockPos pos) { + super.setPos(pos); + if (this.block.components.has(MCBlockTransform.class)) + this.block.components.remove(MCBlockTransform.class); + this.block.components.add(new MCBlockTransform(this.block, Game.natives().toNova(this.getWorld()), Game.natives().toNova(this.getPos()))); + } + + private static class FWPacketUpdateTileEntity extends SPacketUpdateTileEntity { + private final Packet packet; + + public FWPacketUpdateTileEntity(Packet packet, BlockPos blockPosIn, int metadataIn, NBTTagCompound compoundIn) { + super(blockPosIn, metadataIn, compoundIn); + this.packet = packet; + } + + @Override + public void processPacket(INetHandlerPlayClient handler) { + super.processPacket(handler); + try { + this.packet.processPacket((T) handler); + } catch (ClassCastException | NoSuchMethodError e) { + // Why did Mojang incompatibly replace getDescriptionPacket() with getUpdatePacket(). + } + } + + @Override + public void writePacketData(PacketBuffer buf) throws IOException { + super.writePacketData(buf); + this.packet.writePacketData(buf); + } + + @Override + public void readPacketData(PacketBuffer buf) throws IOException { + super.readPacketData(buf); + this.packet.readPacketData(buf); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileLoader.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileLoader.java new file mode 100644 index 000000000..cf7e53f08 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileLoader.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import nova.core.block.Block; +import nova.core.block.BlockFactory; +import nova.core.component.Updater; +import nova.core.component.fluid.SidedTankProvider; +import nova.core.util.Direction; +import nova.core.wrapper.mc.forge.v1_11.asm.lib.ComponentInjector; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; +import nova.internal.core.Game; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +/** + * @author Vic Nightfall + */ +public final class FWTileLoader { + + private static ComponentInjector injector = new ComponentInjector<>(FWTile.class); + private static ComponentInjector updaterInjector = new ComponentInjector<>(FWTileUpdater.class); + + private FWTileLoader() { + } + + public static FWTile loadTile(NBTTagCompound data) { + try { + String blockID = data.getString("novaID"); + Block block = createBlock(blockID); + FWTile tile = (block instanceof Updater) ? updaterInjector.inject(block, new Class[0], new Object[0]) : + injector.inject(block, new Class[0], new Object[0]); + tile.setBlock(block); + WrapperEvent.FWTileCreate event = new WrapperEvent.FWTileCreate(block, tile); + Game.events().publish(event); + return tile; + } catch (Exception e) { + throw new RuntimeException("Fatal error when trying to create a new NOVA tile.", e); + } + } + + public static FWTile loadTile(String blockID) { + try { + Block block = createBlock(blockID); + FWTile tile = (block instanceof Updater) ? updaterInjector.inject(block, new Class[] { String.class }, new Object[] { blockID }) : + injector.inject(block, new Class[] { String.class }, new Object[] { blockID }); + tile.setBlock(block); + WrapperEvent.FWTileCreate event = new WrapperEvent.FWTileCreate(block, tile); + Game.events().publish(event); + return tile; + } catch (Exception e) { + throw new RuntimeException("Fatal error when trying to create a new NOVA tile.", e); + } + } + + private static Block createBlock(String blockID) { + Optional blockFactory = Game.blocks().get(blockID); + if (blockFactory.isPresent()) { + return blockFactory.get().build(); + } else { + throw new RuntimeException("Error! Invalid NOVA block ID: " + blockID); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileRenderer.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileRenderer.java new file mode 100644 index 000000000..8a3ec4231 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileRenderer.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.tileentity.TileEntity; +import nova.core.block.Block; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.wrapper.mc.forge.v1_11.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward.BWModel; + +import java.util.Optional; + +import static org.lwjgl.opengl.GL11.GL_QUADS; + +/** + * @author Calclavia + */ +public class FWTileRenderer extends TileEntitySpecialRenderer { + + public static final FWTileRenderer instance = new FWTileRenderer(); + + @Override + public void renderTileEntityAt(FWTile te, double x, double y, double z, float p_180535_8_, int p_180535_9_) { + Block block = te.getBlock(); + Optional opRenderer = block.components.getOp(DynamicRenderer.class); + if (opRenderer.isPresent()) { + BWModel model = new BWModel(); + model.matrix.translate(x + 0.5, y + 0.5, z + 0.5); + opRenderer.get().onRender.accept(model); + bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); + RenderUtility.enableBlending(); + Tessellator.getInstance().getBuffer().begin(GL_QUADS, DefaultVertexFormats.BLOCK); + model.render(); + Tessellator.getInstance().draw(); + RenderUtility.disableBlending(); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileUpdater.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileUpdater.java new file mode 100644 index 000000000..75b6bcdf7 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/FWTileUpdater.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.util.ITickable; +import nova.core.component.Updater; + +/** + * @author Calclavia + */ +public class FWTileUpdater extends FWTile implements ITickable { + public FWTileUpdater() { + + } + + public FWTileUpdater(String blockID) { + this.blockID = blockID; + } + + /** + * Updates the block. + */ + @Override + public void update() { + if (block != null) { + ((Updater) block).update(0.05); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/MCBlockTransform.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/MCBlockTransform.java new file mode 100644 index 000000000..3d4fca20e --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/MCBlockTransform.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import nova.core.block.Block; +import nova.core.component.transform.BlockTransform; +import nova.core.world.World; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * @author Calclavia + */ +public class MCBlockTransform extends BlockTransform { + + public final Block block; + public final World world; + public final Vector3D position; + + public MCBlockTransform(Block block, World world, Vector3D position) { + this.block = block; + this.world = world; + this.position = position; + } + + @Override + public Vector3D position() { + return position; + } + + @Override + public World world() { + return world; + } + + @Override + public void setWorld(World world) { + this.world.removeBlock(position); + world.setBlock(position, block.getFactory()); + } + + @Override + public void setPosition(Vector3D position) { + world.removeBlock(position); + world.setBlock(position, block.getFactory()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/ProxyMaterial.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/ProxyMaterial.java new file mode 100644 index 000000000..46b2848ca --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/forward/ProxyMaterial.java @@ -0,0 +1,34 @@ +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward; + +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import nova.core.block.component.BlockProperty; +import nova.core.block.component.BlockProperty.Opacity; + +/** + * @author soniex2 + */ +public class ProxyMaterial extends Material { + private final Opacity opacity; + + /** + * Construct a new proxy material. + * @param color The map color. + * @param opacity The Opacity to use. + */ + public ProxyMaterial(MapColor color, Opacity opacity) { + super(color); + this.opacity = opacity; + } + + @Override + public boolean blocksLight() { + return opacity.allowsLightThrough; + } + + @Override + public boolean isOpaque() { + return opacity.allowsLightThrough; + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/world/BWWorld.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/world/BWWorld.java new file mode 100644 index 000000000..36a6055bf --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/world/BWWorld.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.world; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import nova.core.block.Block; +import nova.core.block.BlockFactory; +import nova.core.entity.Entity; +import nova.core.entity.EntityFactory; +import nova.core.item.Item; +import nova.core.sound.Sound; +import nova.core.util.shape.Cuboid; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.backward.BWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.MCBlockTransform; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.MCEntityTransform; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; + +/** + * The backwards world wrapper. + * @author Calclavia + */ +public class BWWorld extends World { + public final net.minecraft.world.IBlockAccess access; + + public BWWorld(net.minecraft.world.IBlockAccess blockAccess) { + this.access = blockAccess; + } + + public net.minecraft.world.World world() { + // Trying to access world from a IBlockAccess object! + assert access instanceof World; + return (net.minecraft.world.World) access; + } + + @Override + public void markStaticRender(Vector3D position) { + BlockPos pos = new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ()); + world().markBlockRangeForRenderUpdate(pos, pos); + } + + @Override + public void markChange(Vector3D position) { + world().notifyNeighborsOfStateChange( + new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ()), + access.getBlockState(new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ())).getBlock(), + true + ); + } + + @Override + public Optional getBlock(Vector3D position) { + net.minecraft.block.Block mcBlock = access.getBlockState(new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ())).getBlock(); + if (mcBlock == null || mcBlock == Blocks.AIR) { + Block airBlock = Game.blocks().getAirBlock().build(); + airBlock.components.add(new MCBlockTransform(airBlock, this, position)); + return Optional.of(airBlock); + } else if (mcBlock instanceof FWBlock) { + return Optional.of(((FWBlock) mcBlock).getBlockInstance(access, position)); + } else { + return Optional.of(new BWBlock(mcBlock, this, position)); + } + } + + @Override + public boolean setBlock(Vector3D position, BlockFactory blockFactory) { + //TODO: Do not call blockFactory.build() + net.minecraft.block.Block mcBlock = Game.natives().toNative(blockFactory.build()); + BlockPos pos = new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ()); + net.minecraft.block.Block actualBlock = mcBlock != null ? mcBlock : Blocks.AIR; + IBlockState defaultState = actualBlock.getDefaultState(); + IBlockState extendedState = actualBlock.getExtendedState(defaultState, world(), pos); + return world().setBlockState(pos, extendedState); + } + + @Override + public boolean removeBlock(Vector3D position) { + return world().setBlockToAir(new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ())); + } + + @Override + public Entity addEntity(EntityFactory factory) { + FWEntity bwEntity = new FWEntity(world(), factory); + bwEntity.forceSpawn = true; + world().spawnEntity(bwEntity); + return bwEntity.getWrapped(); + } + + @Override + public Entity addClientEntity(EntityFactory factory) { + return NovaMinecraft.proxy.spawnParticle(world(), factory); + } + + @Override + public Entity addClientEntity(Entity entity) { + return NovaMinecraft.proxy.spawnParticle(world(), entity); + } + + @Override + public void removeEntity(Entity entity) { + net.minecraft.entity.Entity wrapper = entity.components.get(MCEntityTransform.class).wrapper; + wrapper.setDead(); + world().removeEntity(wrapper); + } + + @Override + public Set getEntities(Cuboid bound) { + return (Set) world() + .getEntitiesWithinAABB(net.minecraft.entity.Entity.class, new AxisAlignedBB(bound.min.getX(), bound.min.getY(), bound.min.getZ(), bound.max.getX(), bound.max.getY(), bound.max.getZ())) + .stream() + .map(mcEnt -> Game.natives().getNative(Entity.class, net.minecraft.entity.Entity.class).toNova((net.minecraft.entity.Entity) mcEnt)) + .collect(Collectors.toSet()); + } + + @Override + public Entity addEntity(Vector3D position, Item item) { + EntityItem entityItem = new EntityItem(world(), position.getX(), position.getY(), position.getZ(), Game.natives().toNative(item)); + world().spawnEntity(entityItem); + return Game.natives().toNova(entityItem); + } + + @Override + public Optional getEntity(String uniqueID) { + return Optional.ofNullable(Game.natives().toNova(world().getEntityByID(Integer.parseInt(uniqueID)))); + } + + @Override + public String getID() { + return world().provider.getDimensionType().getName(); + } + + @Override + public void playSoundAtPosition(Vector3D position, Sound sound) { + world().playSound(position.getX(), position.getY(), position.getZ(), SoundEvent.REGISTRY.getObject(new ResourceLocation(sound.getID())), SoundCategory.BLOCKS, sound.volume, sound.pitch, true); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/world/WorldConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/world/WorldConverter.java new file mode 100644 index 000000000..aeee56881 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/block/world/WorldConverter.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.block.world; + +import net.minecraft.world.IBlockAccess; +import nova.core.nativewrapper.NativeConverter; +import nova.core.world.World; +import nova.internal.core.Game; + +import java.util.Optional; + +/** + * @author Calclavia + */ +public class WorldConverter implements NativeConverter { + @Override + public Class getNovaSide() { + return World.class; + } + + @Override + public Class getNativeSide() { + return IBlockAccess.class; + } + + @Override + public World toNova(IBlockAccess nativeObj) { + if (nativeObj instanceof net.minecraft.world.World) { + Optional opWorld = Game.worlds().findWorld(((net.minecraft.world.World) nativeObj).provider.getDimensionType().getName()); + if (opWorld.isPresent()) { + return opWorld.get(); + } + } + + return new BWWorld(nativeObj); + } + + @Override + public IBlockAccess toNative(World novaObj) { + if (novaObj instanceof BWWorld) { + return ((BWWorld) novaObj).world(); + } + + //TODO: Right exception? + throw new RuntimeException("Attempt to convert a world that is not a BWWorld!"); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/capability/forward/FWCapabilityProvider.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/capability/forward/FWCapabilityProvider.java new file mode 100644 index 000000000..ff4c731c3 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/capability/forward/FWCapabilityProvider.java @@ -0,0 +1,63 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package nova.core.wrapper.mc.forge.v1_11.wrapper.capability.forward; + +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import nova.core.util.EnumSelector; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author ExE Boss + */ +public class FWCapabilityProvider implements ICapabilityProvider { + + private final Map, Object> capabilities = new HashMap<>(); + private final Map, Object>> sidedCapabilities = new HashMap<>(); + + public FWCapabilityProvider() { + for (EnumFacing facing : EnumFacing.VALUES) + sidedCapabilities.put(facing, new HashMap<>()); + } + + public boolean hasCapabilities() { + return !capabilities.isEmpty() || sidedCapabilities.values().stream().flatMap(map -> map.keySet().stream()).count() > 0; + } + + public T addCapability(Capability capability, T capabilityInstance, EnumSelector facing) { + if (facing == null || facing.allowsAll()) { + if (capabilities.containsKey(capability)) + throw new IllegalArgumentException("Already has capability " + capabilityInstance.getClass()); + + capabilities.put(capability, capabilityInstance); + } else { + facing.forEach(enumFacing -> { + Map, Object> capabilities = sidedCapabilities.get(enumFacing); + + if (capabilities.containsKey(capability)) + throw new IllegalArgumentException("Already has capability " + capabilityInstance.getClass()); + + capabilities.put(capability, capabilityInstance); + }); + } + return capabilityInstance; + } + + @Override + public boolean hasCapability(Capability capability, EnumFacing facing) { + return (facing != null ? sidedCapabilities.get(facing).containsValue(capability) : capabilities.containsValue(capability)); + } + + @Override + public T getCapability(Capability capability, EnumFacing facing) { + if (!hasCapability(capability, facing)) return null; + return (T) (facing != null ? sidedCapabilities.get(facing).get(capability) : capabilities.get(capability)); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/cuboid/CuboidConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/cuboid/CuboidConverter.java new file mode 100644 index 000000000..127e6ffd7 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/cuboid/CuboidConverter.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.cuboid; + +import net.minecraft.util.math.AxisAlignedBB; +import nova.core.nativewrapper.NativeConverter; +import nova.core.util.shape.Cuboid; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * @author Calclavia + */ +public class CuboidConverter implements NativeConverter { + @Override + public Class getNovaSide() { + return Cuboid.class; + } + + @Override + public Class getNativeSide() { + return AxisAlignedBB.class; + } + + @Override + public Cuboid toNova(AxisAlignedBB aabb) { + return new Cuboid(new Vector3D(aabb.minX, aabb.minY, aabb.minZ), new Vector3D(aabb.maxX, aabb.maxY, aabb.maxZ)); + } + + @Override + public AxisAlignedBB toNative(Cuboid cuboid) { + return new AxisAlignedBB(cuboid.min.getX(), cuboid.min.getY(), cuboid.min.getZ(), cuboid.max.getX(), cuboid.max.getY(), cuboid.max.getZ()); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/data/DataWrapper.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/data/DataWrapper.java new file mode 100644 index 000000000..b452e2747 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/data/DataWrapper.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.data; + +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagByte; +import net.minecraft.nbt.NBTTagByteArray; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagDouble; +import net.minecraft.nbt.NBTTagFloat; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.nbt.NBTTagIntArray; +import net.minecraft.nbt.NBTTagLong; +import net.minecraft.nbt.NBTTagShort; +import net.minecraft.nbt.NBTTagString; +import nova.core.nativewrapper.NativeConverter; +import nova.core.retention.Data; +import nova.internal.core.Game; + +import java.util.Set; + +/** + * Utility that manages common NBT queueSave and load methods + * @author Calclavia + */ +public class DataWrapper implements NativeConverter { + + public static DataWrapper instance() { + return (DataWrapper) Game.natives().getNative(Data.class, NBTTagCompound.class); + } + + @Override + public Class getNovaSide() { + return Data.class; + } + + @Override + public Class getNativeSide() { + return NBTTagCompound.class; + } + + @Override + public Data toNova(NBTTagCompound nbt) { + Data data = new Data(); + if (nbt != null) { + data.className = nbt.getString("class"); + Set keys = nbt.getKeySet(); + keys.forEach(k -> data.put(k, load(nbt, k))); + } + return data; + } + + @Override + public NBTTagCompound toNative(Data data) { + if (data == null) { + return null; + } + + return toNative(new NBTTagCompound(), data); + } + + public NBTTagCompound toNative(NBTTagCompound nbt, Data data) { + if (data.className != null) { + nbt.setString("class", data.className); + } + data.forEach((k, v) -> save(nbt, k, v)); + return nbt; + } + + /** + * Saves an unknown object to NBT + * @param tag - NBTTagCompound to queueSave the tag too + * @param key - name to queueSave the object as + * @param value - the actual object + * @return the tag when done saving too i + */ + public NBTTagCompound save(NBTTagCompound tag, String key, Object value) { + if (value instanceof Boolean) { + tag.setBoolean("isBoolean", true); + tag.setBoolean(key, (boolean) value); + } else if (value instanceof Byte) { + tag.setBoolean("isBoolean", false); + tag.setByte(key, (byte) value); + } else if (value instanceof Short) { + tag.setShort(key, (short) value); + } else if (value instanceof Integer) { + tag.setInteger(key, (int) value); + } else if (value instanceof Long) { + tag.setLong(key, (long) value); + } else if (value instanceof Character) { + tag.setInteger(key, (Character) value); + } else if (value instanceof Float) { + tag.setFloat(key, (float) value); + } else if (value instanceof Double) { + tag.setDouble(key, (double) value); + } else if (value instanceof String) { + tag.setString(key, (String) value); + } else if (value instanceof Data) { + NBTTagCompound innerTag = new NBTTagCompound(); + toNative(innerTag, (Data) value); + tag.setTag(key, innerTag); + } + return tag; + } + + /** + * Reads an unknown object withPriority a known name from NBT + * @param tag - tag to read the value from + * @param key - name of the value + * @return object or suggestionValue if nothing is found + */ + public Object load(NBTTagCompound tag, String key) { + if (tag != null && key != null) { + NBTBase saveTag = tag.getTag(key); + + if (saveTag instanceof NBTTagFloat) { + return tag.getFloat(key); + } else if (saveTag instanceof NBTTagDouble) { + return tag.getDouble(key); + } else if (saveTag instanceof NBTTagInt) { + return tag.getInteger(key); + } else if (saveTag instanceof NBTTagString) { + return tag.getString(key); + } else if (saveTag instanceof NBTTagShort) { + return tag.getShort(key); + } else if (saveTag instanceof NBTTagByte) { + if (tag.getBoolean("isBoolean")) { + return tag.getBoolean(key); + } else { + return tag.getByte(key); + } + } else if (saveTag instanceof NBTTagLong) { + return tag.getLong(key); + } else if (saveTag instanceof NBTTagByteArray) { + return tag.getByteArray(key); + } else if (saveTag instanceof NBTTagIntArray) { + return tag.getIntArray(key); + } else if (saveTag instanceof NBTTagCompound) { + NBTTagCompound innerTag = tag.getCompoundTag(key); + return toNova(innerTag); + } + } + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/EntityConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/EntityConverter.java new file mode 100644 index 000000000..da3e8f418 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/EntityConverter.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.entity; + +import net.minecraft.util.EnumParticleTypes; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nova.core.entity.Entity; +import nova.core.entity.EntityFactory; +import nova.core.loader.Loadable; +import nova.core.nativewrapper.NativeConverter; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward.BWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.particle.backward.BWParticle; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.MCEntityTransform; +import nova.internal.core.Game; + +import java.util.Optional; + +public class EntityConverter implements NativeConverter, Loadable { + + @Override + public Class getNovaSide() { + return Entity.class; + } + + @Override + public Class getNativeSide() { + return net.minecraft.entity.Entity.class; + } + + @Override + public Entity toNova(net.minecraft.entity.Entity mcEntity) { + //Prevents dual wrapping + if (mcEntity instanceof FWEntity) { + return ((FWEntity) mcEntity).getWrapped(); + } + + //TODO: Make this BWRegistry non-lazy + //Lazy registry + String id = mcEntity.getClass().getName(); + Optional entityFactory = Game.entities().get(id); + + if (entityFactory.isPresent()) { + return entityFactory.get().build(); + } else { + return Game.entities().register(id, () -> new BWEntity(mcEntity)).build(); + } + } + + @Override + public net.minecraft.entity.Entity toNative(Entity novaObj) { + MCEntityTransform transform = novaObj.components.get(MCEntityTransform.class); + + if (transform.wrapper instanceof FWEntity) { + return transform.wrapper; + } + + throw new IllegalArgumentException("Entity wrapper is invalid (where did this object come from?)"); + } + + @Override + @SideOnly(Side.CLIENT) + public void preInit() { + /** + * Backward register all particle effects + */ + //Look up for particle factory and pass it into BWParticle + for (EnumParticleTypes type : EnumParticleTypes.values()) { + Game.entities().register(Game.info().name + ":" + type.getParticleName(), () -> new BWParticle(type.getParticleID())); + } + } +} \ No newline at end of file diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/backward/BWEntity.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/backward/BWEntity.java new file mode 100644 index 000000000..97842c06f --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/backward/BWEntity.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.DamageSource; +import nova.core.component.inventory.InventoryPlayer; +import nova.core.component.misc.Damageable; +import nova.core.entity.Entity; +import nova.core.entity.component.Living; +import nova.core.entity.component.Player; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.MCEntityTransform; +import nova.core.wrapper.mc.forge.v1_11.wrapper.inventory.BWInventory; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * A Minecraft to NOVA Entity wrapper + * @author Calclavia + */ +//TODO: Incomplete. Add more components! +public class BWEntity extends Entity { + + public net.minecraft.entity.Entity entity; + + public BWEntity(net.minecraft.entity.Entity entity) { + this.entity = entity; + if (entity != null) { + components.add(new MCEntityTransform(entity)); + components.add(new Damageable() { + @Override + public void damage(double amount, DamageType type) { + if (type == DamageType.generic) { + entity.attackEntityFrom(DamageSource.GENERIC, (float) amount); + } + // TODO: Apply other damage source wrappers? + } + }); + } + + if (entity instanceof EntityLivingBase) { + if (entity instanceof EntityPlayer) { + MCPlayer player = components.add(new MCPlayer(this)); + player.faceDisplacement = () -> Vector3D.PLUS_J.scalarMultiply(entity.getEyeHeight()); + } else { + Living living = components.add(new Living()); + living.faceDisplacement = () -> Vector3D.PLUS_J.scalarMultiply(entity.getEyeHeight()); + } + } + + WrapperEvent.BWEntityCreate event = new WrapperEvent.BWEntityCreate(this, entity); + Game.events().publish(event); + } + + public static class MCPlayer extends Player { + public final BWEntity bwEntity; + public final EntityPlayer entity; + public final BWInventoryPlayer inventory; + + public MCPlayer(BWEntity bwEntity) { + this.bwEntity = bwEntity; + this.entity = (EntityPlayer) bwEntity.entity; + this.inventory = new BWInventoryPlayer(entity); + } + + @Override + public Entity entity() { + return bwEntity; + } + + @Override + public String getUsername() { + return entity.getGameProfile().getName(); + } + + @Override + public String getID() { + return entity.getGameProfile().getId().toString(); + } + + @Override + public InventoryPlayer getInventory() { + return inventory; + } + + @Override + public String getDisplayName() { + return entity.getDisplayName().getUnformattedText(); + } + } + + public static class BWInventoryPlayer extends BWInventory implements InventoryPlayer { + public final EntityPlayer entity; + + public BWInventoryPlayer(EntityPlayer entity) { + super(entity.inventory); + this.entity = entity; + } + + @Override + public int getHeldSlot() { + return entity.inventory.currentItem; + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/BWRigidBody.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/BWRigidBody.java new file mode 100644 index 000000000..e5bd7d97d --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/BWRigidBody.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward; + +import net.minecraft.entity.MoverType; +import nova.core.entity.Entity; +import nova.core.entity.component.RigidBody; +import nova.core.util.math.RotationUtil; +import nova.core.util.math.Vector3DUtil; +import org.apache.commons.math3.geometry.euclidean.threed.Rotation; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * Based on the Euler Integration because Minecraft stores the following values: + * + * Position + * Velocity + * @author Calclavia + */ +public class BWRigidBody extends RigidBody { + private double mass = 1; + + /** + * Translation + */ + private double drag = 0; + + private Vector3D gravity = new Vector3D(0, -9.81, 0); + + /** + * Rotation + */ + private double angularDrag = 0; + private Rotation angularVelocity = Rotation.IDENTITY; + + /** + * Translation + */ + private Vector3D netForce = Vector3D.ZERO; + + /** + * Rotation + */ + private Vector3D netTorque = Vector3D.ZERO; + + private net.minecraft.entity.Entity mcEntity() { + return getProvider().components.get(MCEntityTransform.class).wrapper; + } + + private Entity entity() { + return (Entity) getProvider(); + } + + @Override + public void update(double deltaTime) { + updateTranslation(deltaTime); + updateRotation(deltaTime); + } + + void updateTranslation(double deltaTime) { + //Integrate velocity to displacement + Vector3D displacement = velocity().scalarMultiply(deltaTime); + mcEntity().move(MoverType.SELF, displacement.getX(), displacement.getY(), displacement.getZ()); + + //Integrate netForce to velocity + setVelocity(velocity().add(netForce.scalarMultiply(1 / mass()).scalarMultiply(deltaTime))); + + //Clear net force + netForce = Vector3D.ZERO; + + //Apply drag + addForce(velocity().negate().scalarMultiply(drag())); + if (!mcEntity().onGround) { + //Apply gravity + addForce(gravity().scalarMultiply(mass())); + } + } + + void updateRotation(double deltaTime) { + + //Integrate angular velocity to angular displacement + Rotation angularVel = angularVelocity(); + Rotation deltaRotation = RotationUtil.slerp(Rotation.IDENTITY, angularVel, deltaTime); + entity().transform().setRotation(entity().rotation().applyTo(deltaRotation)); + + //Integrate torque to angular velocity + Vector3D torque = netTorque.scalarMultiply(deltaTime); + if (!Vector3D.ZERO.equals(torque)) { + setAngularVelocity(angularVelocity().applyTo(new Rotation(Vector3DUtil.FORWARD, torque))); + } + + //Clear net torque + netTorque = Vector3D.ZERO; + + //Apply drag + Vector3D eulerAngularVel = angularVelocity().applyInverseTo(Vector3DUtil.FORWARD); + addTorque(eulerAngularVel.negate().scalarMultiply(angularDrag())); + } + + @Override + public Vector3D getVelocity() { + return new Vector3D(mcEntity().motionX, mcEntity().motionY, mcEntity().motionZ); + } + + @Override + public void setVelocity(Vector3D velocity) { + mcEntity().motionX = velocity.getX(); + mcEntity().motionY = velocity.getY(); + mcEntity().motionZ = velocity.getZ(); + } + + @Override + public void addForce(Vector3D force, Vector3D position) { + //TODO: implement + } + + @Override + public void addTorque(Vector3D torque) { + //TODO: implement + } + + @Override + public void addForce(Vector3D force) { + netForce = netForce.add(force.scalarMultiply(1 / mass())); + } + + /** + * Mass in kilograms. Default is 1 kg. + */ + @Override + public double getMass() { + return mass; + } + + @Override + public void setMass(double mass) { + this.mass = mass; + } + + @Override + public double getDrag() { + return drag; + } + + @Override + public void setDrag(double drag) { + this.drag = drag; + } + + /** + * Gravity is an acceleration. + */ + @Override + public Vector3D getGravity() { + return gravity; + } + + @Override + public void setGravity(Vector3D gravity) { + this.gravity = gravity; + } + + /** + * Rotation Methods + */ + @Override + public double getAngularDrag() { + return angularDrag; + } + + @Override + public void setAngularDrag(double angularDrag) { + this.angularDrag = angularDrag; + } + + @Override + public Rotation getAngularVelocity() { + return angularVelocity; + } + + @Override + public void setAngularVelocity(Rotation angularVelocity) { + this.angularVelocity = angularVelocity; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/FWEntity.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/FWEntity.java new file mode 100644 index 000000000..b66b3d077 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/FWEntity.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward; + +import io.netty.buffer.ByteBuf; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import nova.core.block.Stateful; +import nova.core.component.Updater; +import nova.core.component.misc.Collider; +import nova.core.component.transform.EntityTransform; +import nova.core.entity.Entity; +import nova.core.entity.EntityFactory; +import nova.core.retention.Data; +import nova.core.retention.Storable; +import nova.core.util.EnumSelector; +import nova.core.util.shape.Cuboid; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11.wrapper.data.DataWrapper; +import nova.internal.core.Game; + +import java.util.HashMap; +import java.util.Map; + +/** + * Entity wrapper + * @author Calclavia + */ +public class FWEntity extends net.minecraft.entity.Entity implements IEntityAdditionalSpawnData { + + private final Map, Object> capabilities = new HashMap<>(); + private final Map, Object>> sidedCapabilities = new HashMap<>(); + + protected final EntityTransform transform; + protected Entity wrapped; + boolean firstTick = true; + + public FWEntity(World worldIn) { + super(worldIn); + this.transform = new MCEntityTransform(this); + } + + public FWEntity(World world, EntityFactory factory) { + this(world); + setWrapped(factory.build()); + entityInit(); + } + + @Override + protected void readEntityFromNBT(NBTTagCompound nbt) { + if (wrapped instanceof Storable) { + ((Storable) wrapped).load(Game.natives().toNova(nbt)); + } + if (wrapped == null) { + //This entity was saved to disk. + setWrapped(Game.entities().get(nbt.getString("novaID")).get().build()); + } + } + + @Override + protected void writeEntityToNBT(NBTTagCompound nbt) { + if (wrapped instanceof Storable) { + Data data = new Data(); + ((Storable) wrapped).save(data); + DataWrapper.instance().toNative(nbt, data); + } + nbt.setString("novaID", wrapped.getID()); + } + + @Override + public void writeSpawnData(ByteBuf buffer) { + //Write the ID of the entity to client + String id = wrapped.getID(); + char[] chars = id.toCharArray(); + buffer.writeInt(chars.length); + + for (char c : chars) + buffer.writeChar(c); + } + + @Override + public void readSpawnData(ByteBuf buffer) { + //Load the client ID + String id = ""; + int length = buffer.readInt(); + for (int i = 0; i < length; i++) + id += buffer.readChar(); + + setWrapped(Game.entities().get(id).get().build()); + } + + public Entity getWrapped() { + return wrapped; + } + + private void setWrapped(Entity wrapped) { + this.wrapped = wrapped; + wrapped.components.add(transform); + } + + public EntityTransform getTransform() { + return transform; + } + + /** + * All methods below here are exactly the same between FWEntity and FWEntityFX. + * ***************************************************************************** + */ + @Override + protected void entityInit() { + //MC calls entityInit() before we finish wrapping, so this variable is required to check if wrapped exists. + if (wrapped != null) { + wrapped.events.publish(new Stateful.LoadEvent()); + updateCollider(); + WrapperEvent.FWEntityCreate event = new WrapperEvent.FWEntityCreate(wrapped, this); + Game.events().publish(event); + } + } + + @Override + public void onUpdate() { + if (wrapped != null) { + if (firstTick) { + prevPosX = posX; + prevPosY = posY; + prevPosZ = posZ; + setPosition(posX, posY, posZ); + firstTick = false; + } + + //onEntityUpdate(); + + double deltaTime = 0.05; + + if (wrapped instanceof Updater) { + ((Updater) wrapped).update(deltaTime); + } + + updateCollider(); + + /** + * Update all components in the entity. + */ + wrapped.components() + .stream() + .filter(component -> component instanceof Updater) + .forEach(component -> ((Updater) component).update(deltaTime)); + } else { + Game.logger().error("Ticking entity without wrapped entity object."); + } + } + + /** + * Wraps the entity collider values + */ + public void updateCollider() { + //Wrap entity collider + if (wrapped.components.has(Collider.class)) { + Collider collider = wrapped.components.get(Collider.class); + + //Transform cuboid based on entity. + Cuboid size = collider + .boundingBox + .get(); + ///.scalarMultiply(transform.scale()); + + setBounds(size); + } + } + + @Override + protected void setSize(float width, float height) { + if (width != this.width || height != this.height) { + this.width = width; + this.height = height; + setBounds(new Cuboid(-width / 2, -height / 2, -width / 2, width / 2, height / 2, width / 2)); + } + } + + @Override + public void setPosition(double x, double y, double z) { + this.posX = x; + this.posY = y; + this.posZ = z; + //Reset the bounding box + if (getCollisionBoundingBox() != null) { + setBounds(Game.natives().toNova(getCollisionBoundingBox())); + } + } + + /** + * Sets the bounding box of the entity based on NOVA cuboid bounds + * @param bounds NOVA Cuboid bounds + */ + public void setBounds(Cuboid bounds) { + //TODO: Fix moveEntity auto-centering + if (transform != null) { + setEntityBoundingBox(Game.natives().toNative(bounds.add(transform.position()))); + } + } + + @Override + public void setDead() { + wrapped.events.publish(new Stateful.UnloadEvent()); + super.setDead(); + } + + public T addCapability(Capability capability, T capabilityInstance, EnumSelector facing) { + if (facing == null || facing.allowsAll()) { + if (capabilities.containsKey(capability)) + throw new IllegalArgumentException("Already has capability " + capabilityInstance.getClass()); + + capabilities.put(capability, capabilityInstance); + } else { + facing.forEach(enumFacing -> { + Map, Object> capabilities = sidedCapabilities.get(enumFacing); + + if (capabilities.containsKey(capability)) + throw new IllegalArgumentException("Already has capability " + capabilityInstance.getClass()); + + capabilities.put(capability, capabilityInstance); + }); + } + return capabilityInstance; + } + + @Override + public boolean hasCapability(Capability capability, EnumFacing facing) { + return (facing != null ? sidedCapabilities.get(facing).containsValue(capability) : capabilities.containsValue(capability)) + || super.hasCapability(capability, facing); + } + + @Override + public T getCapability(Capability capability, EnumFacing facing) { + if (!hasCapability(capability, facing)) return null; + T capabilityInstance = (T) (facing != null ? sidedCapabilities.get(facing).get(capability) : capabilities.get(capability)); + return capabilityInstance != null ? capabilityInstance : super.getCapability(capability, facing); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/FWEntityRenderer.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/FWEntityRenderer.java new file mode 100644 index 000000000..be3853f79 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/FWEntityRenderer.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.client.registry.IRenderFactory; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.wrapper.mc.forge.v1_11.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11.wrapper.particle.forward.FWParticle; +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward.BWModel; +import org.lwjgl.opengl.GL11; + +import java.util.Optional; + +import static org.lwjgl.opengl.GL11.GL_BLEND; +import static org.lwjgl.opengl.GL11.GL_SMOOTH; +import static org.lwjgl.opengl.GL11.GL_QUADS; +import static org.lwjgl.opengl.GL11.glEnable; +import static org.lwjgl.opengl.GL11.glShadeModel; + +/** + * Renders entities. + * @author Calclavia + */ +public class FWEntityRenderer extends Render { + public static final IRenderFactory instance = FWEntityRenderer::new; + + public FWEntityRenderer(RenderManager manager) { + super(manager); + } + + public static void render(FWParticle wrapper, nova.core.entity.Entity entity, double x, double y, double z) { + Optional opRenderer = entity.components.getOp(DynamicRenderer.class); + + if (opRenderer.isPresent()) { + BWModel model = new BWModel(); + model.matrix + .translate(x, y, z) + .scale(entity.scale()) + .translate(entity.pivot()) + .rotate(entity.rotation()) + .translate(entity.pivot().negate()); + + opRenderer.get().onRender.accept(model); + + if (model.blendSFactor > 0 && model.blendDFactor > 0) { + glShadeModel(GL_SMOOTH); + glEnable(GL_BLEND); + GL11.glBlendFunc(model.blendSFactor, model.blendDFactor); + } + + Tessellator.getInstance().getBuffer().begin(GL_QUADS, DefaultVertexFormats.BLOCK); + model.render(Optional.of(Minecraft.getMinecraft().getRenderManager())); + Tessellator.getInstance().draw(); + + if (model.blendSFactor > 0 && model.blendDFactor > 0) { + RenderUtility.disableBlending(); + } + } + } + + public static void render(FWEntity wrapper, nova.core.entity.Entity entity, double x, double y, double z) { + Optional opRenderer = entity.components.getOp(DynamicRenderer.class); + + if (opRenderer.isPresent()) { + BWModel model = new BWModel(); + model.matrix + .translate(x, y, z) + .scale(entity.scale()) + .translate(entity.pivot()) + .rotate(entity.rotation()) + .translate(entity.pivot().negate()); + + opRenderer.get().onRender.accept(model); + + if (model.blendSFactor > 0 && model.blendDFactor > 0) { + glShadeModel(GL_SMOOTH); + glEnable(GL_BLEND); + GL11.glBlendFunc(model.blendSFactor, model.blendDFactor); + } + + Tessellator.getInstance().getBuffer().begin(GL_QUADS, DefaultVertexFormats.BLOCK); + model.render(Optional.of(Minecraft.getMinecraft().getRenderManager())); + Tessellator.getInstance().draw(); + + if (model.blendSFactor > 0 && model.blendDFactor > 0) { + RenderUtility.disableBlending(); + } + } + } + + @Override + public void doRender(FWEntity entity, double x, double y, double z, float p_76986_8_, float p_76986_9_) { + render(entity, ((FWEntity) entity).wrapped, x, y, z); + } + + @Override + protected ResourceLocation getEntityTexture(FWEntity entity) { + return null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/MCEntityTransform.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/MCEntityTransform.java new file mode 100644 index 000000000..c2a4517b8 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/entity/forward/MCEntityTransform.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ +package nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.common.DimensionManager; +import nova.core.component.transform.EntityTransform; +import nova.core.util.math.RotationUtil; +import nova.core.util.math.Vector3DUtil; +import nova.core.world.World; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Rotation; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Arrays; + +/** + * Wraps Transform3d used in entity + * @author Calclavia + */ +public class MCEntityTransform extends EntityTransform { + public final net.minecraft.entity.Entity wrapper; + + public MCEntityTransform(net.minecraft.entity.Entity wrapper) { + this.wrapper = wrapper; + this.setPivot(Vector3D.ZERO); + this.setScale(Vector3DUtil.ONE); + } + + @Override + public World world() { + return Game.natives().toNova(wrapper.world); + } + + @Override + public void setWorld(World world) { + wrapper.changeDimension(Arrays.stream(DimensionManager.getWorlds()) + .filter(w -> w.getProviderName().equals(world.getID())) + .findAny().get().provider.getDimensionType().getId()); + } + + @Override + public Vector3D position() { + return new Vector3D(wrapper.posX, wrapper.posY, wrapper.posZ); + } + + @Override + public void setPosition(Vector3D position) { + if (wrapper instanceof EntityPlayerMP) { + ((EntityPlayerMP) wrapper).connection.setPlayerLocation(position.getX(), position.getY(), position.getZ(), wrapper.rotationYaw, wrapper.rotationPitch); + } else { + wrapper.setPosition(position.getX(), position.getY(), position.getZ()); + } + } + + @Override + public Rotation rotation() { + return new Rotation(RotationUtil.DEFAULT_ORDER, -Math.toRadians(wrapper.rotationYaw) - Math.PI, -Math.toRadians(wrapper.rotationPitch), 0); + } + + @Override + public void setRotation(Rotation rotation) { + double[] euler = rotation.getAngles(RotationUtil.DEFAULT_ORDER); + wrapper.rotationYaw = (float) Math.toDegrees(euler[0]); + wrapper.rotationPitch = (float) Math.toDegrees(euler[1]); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/BWInventory.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/BWInventory.java new file mode 100644 index 000000000..d2b7303f0 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/BWInventory.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.inventory; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import nova.core.component.inventory.Inventory; +import nova.core.item.Item; +import nova.internal.core.Game; + +import java.util.Optional; + +public class BWInventory implements Inventory { + public final IInventory wrapped; + + public BWInventory(IInventory mcInventory) { + this.wrapped = mcInventory; + } + + @Override + public Optional get(int i) { + ItemStack stackInSlot = wrapped.getStackInSlot(i); + + if (stackInSlot == null) { + return Optional.empty(); + } + + return Optional.of(Game.natives().toNova(stackInSlot)); + } + + @Override + public boolean set(int i, Item item) { + wrapped.setInventorySlotContents(i, Game.natives().toNative(item)); + return true; + } + + @Override + public Optional remove(int slot) { + Optional item = get(slot); + wrapped.setInventorySlotContents(slot, null); + return item; + } + + @Override + public int size() { + return wrapped.getSizeInventory(); + } + + @Override + public void markChanged() { + wrapped.markDirty(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/FWInventory.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/FWInventory.java new file mode 100644 index 000000000..c994c5d07 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/FWInventory.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.inventory; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; +import nova.core.component.inventory.Inventory; +import nova.core.item.Item; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.ItemConverter; + +public class FWInventory implements IInventory { + + public Inventory wrapped; + + public FWInventory(Inventory inventory) { + this.wrapped = inventory; + } + + @Override + public int getSizeInventory() { + return wrapped.size(); + } + + @Override + public boolean isEmpty() { + int i = 0; + for (Item item : wrapped) { + i++; + } + return i == 0; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return ItemConverter.instance().toNative(wrapped.get(slot).orElse(null)); + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + ItemStack stack = getStackInSlot(slot); + ItemStack ret = stack.copy(); + ret.setCount(Math.min(ret.getCount(), amount)); + stack.setCount(stack.getCount() - ret.getCount()); + if (stack.getCount() <= 0) { + setInventorySlotContents(slot, null); + return ItemStack.EMPTY; + } + markDirty(); + return ret; + } + + public ItemStack getStackInSlotOnClosing(int slot) { + return getStackInSlot(slot); + } + + @Override + public ItemStack removeStackFromSlot(int slot) { + ItemStack stack = getStackInSlot(slot); + decrStackSize(slot, stack.getCount()); + return stack; + } + + @Override + public void setInventorySlotContents(int slot, ItemStack stack) { + wrapped.set(slot, stack != null ? ItemConverter.instance().getNovaItem(stack) : null); + } + + @Override + public String getName() { + // TODO Shouldn't be empty? + return ""; + } + + @Override + public boolean hasCustomName() { + return false; + } + + @Override + public ITextComponent getDisplayName() { + return null; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public void markDirty() { + wrapped.markChanged(); + } + + @Override + public boolean isUsableByPlayer(EntityPlayer player) { + // TODO Auto-generated method stub + return true; + } + + @Override + public void openInventory(EntityPlayer playerIn) { + + } + + @Override + public void closeInventory(EntityPlayer playerIn) { + + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack stack) { + // TODO Auto-generated method stub + return true; + } + + @Override + public int getField(int id) { + return 0; + } + + @Override + public void setField(int id, int value) { + + } + + @Override + public int getFieldCount() { + return 0; + } + + @Override + public void clear() { + this.wrapped = null; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/InventoryConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/InventoryConverter.java new file mode 100644 index 000000000..b0812ce20 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/inventory/InventoryConverter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.inventory; + +import net.minecraft.inventory.IInventory; +import nova.core.component.inventory.Inventory; +import nova.core.nativewrapper.NativeConverter; + +/** + * @author Calclavia + */ +public class InventoryConverter implements NativeConverter { + @Override + public Class getNovaSide() { + return Inventory.class; + } + + @Override + public Class getNativeSide() { + return IInventory.class; + } + + @Override + public Inventory toNova(IInventory nativeObj) { + if (nativeObj instanceof FWInventory) { + return ((FWInventory) nativeObj).wrapped; + } + + return new BWInventory(nativeObj); + } + + @Override + public IInventory toNative(Inventory novaObj) { + + if (novaObj instanceof BWInventory) { + return ((BWInventory) novaObj).wrapped; + } + return new FWInventory(novaObj); + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/ItemConverter.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/ItemConverter.java new file mode 100644 index 000000000..0889f48dc --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/ItemConverter.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item; + +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.backward.BWItemFactory; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.backward.BWItem; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward.FWNBTTagCompound; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward.FWItem; +import com.google.common.collect.HashBiMap; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.registry.GameRegistry; +import nova.core.block.BlockFactory; +import nova.core.component.Category; +import nova.core.item.Item; +import nova.core.item.ItemBlock; +import nova.core.item.ItemFactory; +import nova.core.item.ItemManager; +import nova.core.event.ItemEvent; +import nova.core.loader.Loadable; +import nova.core.loader.Mod; +import nova.core.nativewrapper.NativeConverter; +import nova.core.retention.Data; +import nova.core.wrapper.mc.forge.v1_11.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11.util.ModCreativeTab; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.BlockConverter; +import nova.internal.core.Game; +import nova.internal.core.launch.InitializationException; +import nova.internal.core.launch.ModLoader; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * The main class responsible for wrapping items. + * @author Calclavia, Stan Hebben + */ +public class ItemConverter implements NativeConverter, Loadable { + + /** + * A map of all items registered + */ + private final HashBiMap map = HashBiMap.create(); + + public static ItemConverter instance() { + return (ItemConverter) Game.natives().getNative(Item.class, ItemStack.class); + } + + @Override + public Class getNovaSide() { + return Item.class; + } + + @Override + public Class getNativeSide() { + return ItemStack.class; + } + + @Override + public Item toNova(ItemStack itemStack) { + return getNovaItem(itemStack).setCount(itemStack.getCount()); + } + + //TODO: Why is this method separate? + // Maybe because toNova calls setCount on the result of this method? + public Item getNovaItem(ItemStack itemStack) { + if (itemStack.getItemDamage() == net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE) { + // TODO: Deal withPriority wildcard meta values - important for the ore dictionary + return getNovaItem(new ItemStack(itemStack.getItem(), 1, 0)); + } + + if (itemStack.getTagCompound() != null && itemStack.getTagCompound() instanceof FWNBTTagCompound) { + return ((FWNBTTagCompound) itemStack.getTagCompound()).getItem(); + } else { + ItemFactory itemFactory = registerMinecraftMapping(itemStack.getItem(), itemStack.getItemDamage()); + + Data data = itemStack.getTagCompound() != null ? Game.natives().toNova(itemStack.getTagCompound()) : new Data(); + if (!itemStack.getHasSubtypes() && itemStack.getItemDamage() > 0) { + data.put("damage", itemStack.getItemDamage()); + } + + return itemFactory.build(data); + } + } + + @Override + public ItemStack toNative(Item item) { + if (item == null) { + return null; + } + + //Prevent recusive wrapping + if (item instanceof BWItem) { + return ((BWItem) item).makeItemStack(item.count()); + } else { + ItemFactory itemFactory = Game.items().get(item.getID()).get();// TODO? + FWNBTTagCompound tag = new FWNBTTagCompound(item); + + MinecraftItemMapping mapping = get(itemFactory); + if (mapping == null) { + throw new InitializationException("Missing mapping for " + itemFactory.getID()); + } + + ItemStack result = new ItemStack(mapping.item, item.count(), mapping.meta); + result.setTagCompound(tag); + return result; + } + } + + public ItemStack toNative(ItemFactory itemFactory) { + FWNBTTagCompound tag = new FWNBTTagCompound(itemFactory.build()); + + MinecraftItemMapping mapping = get(itemFactory); + if (mapping == null) { + throw new InitializationException("Missing mapping for " + itemFactory.getID()); + } + + ItemStack result = new ItemStack(mapping.item, 1, mapping.meta); + result.setTagCompound(tag); + return result; + } + + public ItemStack toNative(String id) { + return toNative(Game.items().get(id).get().build().setCount(1)); + } + + public MinecraftItemMapping get(ItemFactory item) { + return map.get(item); + } + + public ItemFactory get(MinecraftItemMapping minecraftItem) { + return map.inverse().get(minecraftItem); + } + + /** + * Saves NOVA item into a Minecraft ItemStack. + * + * @param itemStack Minecraft ItemStack. + * @param item NOVA Item. + * @return The modified ItemStack. + */ + public ItemStack updateMCItemStack(ItemStack itemStack, Item item) { + itemStack.setCount(item.count()); + if (itemStack.getCount() <= 0) { + return ItemStack.EMPTY; + } + + itemStack.setTagCompound(Game.natives().toNative(item.getFactory().save(item))); + return itemStack; + } + + /** + * Register all Nova blocks + */ + @Override + public void preInit() { + registerNOVAItemsToMinecraft(); + registerMinecraftItemsToNOVA(); + registerSubtypeResolution(); + } + + private void registerNOVAItemsToMinecraft() { + //There should be no items registered during Native Converter preInit() + // item.registry.forEach(this::registerNOVAItem); + Game.events().on(ItemEvent.Register.class).bind(this::onItemRegistered); + } + + private void onItemRegistered(ItemEvent.Register event) { + registerNOVAItem(event.itemFactory); + } + + private void registerNOVAItem(ItemFactory itemFactory) { + if (map.containsKey(itemFactory)) { + // just a safeguard - don't map stuff twice + return; + } + + net.minecraft.item.Item itemWrapper; + + Item dummy = itemFactory.build(); + if (dummy instanceof ItemBlock) { + BlockFactory blockFactory = ((ItemBlock) dummy).blockFactory; + net.minecraft.block.Block mcBlock = BlockConverter.instance().toNative(blockFactory); + itemWrapper = net.minecraft.item.Item.getItemFromBlock(mcBlock); + if (itemWrapper == null) { + throw new InitializationException("ItemConverter: Missing block: " + itemFactory.getID()); + } + if (!itemFactory.getID().equals(Objects.toString(net.minecraft.item.Item.REGISTRY.getNameForObject(itemWrapper)))) { + System.err.println("[NOVA]: ItemConverter: " + net.minecraft.item.Item.REGISTRY.getNameForObject(itemWrapper) + " != " + itemFactory.getID()); + net.minecraft.item.Item newItemWrapper = net.minecraft.item.Item.getByNameOrId(itemFactory.getID()); + itemWrapper = newItemWrapper != null ? newItemWrapper : itemWrapper; + } + } else { + itemWrapper = new FWItem(itemFactory); + } + + MinecraftItemMapping minecraftItemMapping = new MinecraftItemMapping(itemWrapper, 0); + map.forcePut(itemFactory, minecraftItemMapping); + + // Don't register ItemBlocks twice + if (!(dummy instanceof ItemBlock)) { + NovaMinecraft.proxy.registerItem((FWItem) itemWrapper); + String itemId = itemFactory.getID(); // TODO? + GameRegistry.register(itemWrapper, new ResourceLocation(itemId)); + + if (dummy.components.has(Category.class) && FMLCommonHandler.instance().getSide().isClient()) { + //Add into creative tab + Category category = dummy.components.get(Category.class); + Optional first = Arrays.stream(CreativeTabs.CREATIVE_TAB_ARRAY) + .filter(tab -> tab.getTabLabel().equals(category.name)) + .findFirst(); + if (first.isPresent()) { + itemWrapper.setCreativeTab(first.get()); + } else { + Optional item = category.item; + ModCreativeTab tab = new ModCreativeTab(category.name, item.isPresent() ? Game.natives().toNative(item.get()) : itemWrapper); + itemWrapper.setCreativeTab(tab); + } + } + + System.out.println("[NOVA]: Registered '" + itemFactory.getID() + "' item."); + } + } + + private void registerMinecraftItemsToNOVA() { + Set itemIDs = net.minecraft.item.Item.REGISTRY.getKeys(); + itemIDs.forEach(itemID -> { + net.minecraft.item.Item item = net.minecraft.item.Item.REGISTRY.getObject(itemID); + registerMinecraftMapping(item, 0); + }); + } + + private void registerSubtypeResolution() { + Game.events().on(ItemEvent.IDNotFound.class).bind(this::onIDNotFound); + } + + private void onIDNotFound(ItemEvent.IDNotFound event) { + // if item minecraft:planks:2 is detected, this code will register minecraft:planks:2 dynamically + // we cannot do this up front since there is **NO** reliable way to get the sub-items of an item + + int lastColon = event.id.lastIndexOf(':'); + if (lastColon < 0) { + return; + } + + try { + int meta = Integer.parseInt(event.id.substring(lastColon + 1)); + String itemID = event.id.substring(0, lastColon); + + net.minecraft.item.Item item = (net.minecraft.item.Item) net.minecraft.item.Item.REGISTRY.getObject(new ResourceLocation(itemID)); + if (item == null || !item.getHasSubtypes()) { + return; + } + + event.setRemappedFactory(registerMinecraftMapping(item, meta)); + } catch (NumberFormatException ex) { + } + } + + private ItemFactory registerMinecraftMapping(net.minecraft.item.Item item, int meta) { + MinecraftItemMapping mapping = new MinecraftItemMapping(item, meta); + if (map.inverse().containsKey(mapping)) { + // don't register twice, return the factory instead + return map.inverse().get(mapping); + } + + BWItemFactory itemFactory = new BWItemFactory(item, meta); + map.put(itemFactory, mapping); + + Game.items().register(itemFactory); + + return itemFactory; + } + + /** + * Used to map MC items and their meta to nova item factories. + */ + public final class MinecraftItemMapping { + public final net.minecraft.item.Item item; + public final int meta; + + public MinecraftItemMapping(net.minecraft.item.Item item, int meta) { + this.item = item; + this.meta = item.getHasSubtypes() ? meta : 0; + } + + public MinecraftItemMapping(ItemStack itemStack) { + this.item = itemStack.getItem(); + this.meta = itemStack.getHasSubtypes() ? itemStack.getItemDamage() : 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MinecraftItemMapping that = (MinecraftItemMapping) o; + + if (meta != that.meta) { + return false; + } + if (!item.equals(that.item)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = item.hashCode(); + result = 31 * result + meta; + return result; + } + + @Override + public String toString() { + if (item.getHasSubtypes()) { + return net.minecraft.item.Item.REGISTRY.getNameForObject(item) + ":" + meta; + } else { + return Objects.toString(net.minecraft.item.Item.REGISTRY.getNameForObject(item)); + } + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/ItemWrapperMethods.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/ItemWrapperMethods.java new file mode 100644 index 000000000..5bdd37aff --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/ItemWrapperMethods.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumActionResult; +import net.minecraft.world.World; +import nova.core.item.Item; +import nova.core.item.ItemFactory; +import nova.core.util.Direction; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward.BWEntity; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.List; +import java.util.Optional; + +/** + * An interface implemented by ItemBlockWrapper and ItemWrapper classes to override Minecraft's item events. + * @author Calclavia + */ +public interface ItemWrapperMethods { + + ItemFactory getItemFactory(); + + default void addInformation(ItemStack itemStack, EntityPlayer player, List list, boolean p_77624_4_) { + Item item = Game.natives().toNova(itemStack); + item.setCount(itemStack.getCount()).events.publish(new Item.TooltipEvent(Optional.of(new BWEntity(player)), list)); + getItemFactory().save(item); + } + + default EnumActionResult onItemUse(ItemStack itemStack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) { + Item item = Game.natives().toNova(itemStack); + Item.UseEvent event = new Item.UseEvent(new BWEntity(player), new Vector3D(x, y, z), Direction.fromOrdinal(side), new Vector3D(hitX, hitY, hitZ)); + item.events.publish(event); + ItemConverter.instance().updateMCItemStack(itemStack, item); + return event.action ? EnumActionResult.SUCCESS : EnumActionResult.FAIL; + } + + default ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player) { + Item item = Game.natives().toNova(itemStack); + item.events.publish(new Item.RightClickEvent(new BWEntity(player))); + return ItemConverter.instance().updateMCItemStack(itemStack, item); + } + + default int getColorFromItemStack(ItemStack itemStack, int p_82790_2_) { + return ((Item) Game.natives().toNova(itemStack)).colorMultiplier().argb(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/OreDictionaryIntegration.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/OreDictionaryIntegration.java new file mode 100644 index 000000000..245f6f6d1 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/OreDictionaryIntegration.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import nova.core.item.Item; +import nova.core.item.ItemDictionary; +import nova.core.util.Dictionary; +import nova.core.wrapper.mc.forge.v1_11.util.ReflectionUtil; +import nova.internal.core.Game; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Stan on 8/02/2015. + */ +public class OreDictionaryIntegration { + public static final OreDictionaryIntegration instance = new OreDictionaryIntegration(); + private static final List> OREDICT_CONTENTS = ReflectionUtil.getOreIdStacks(); + + private OreDictionaryIntegration() { + } + + public void registerOreDictionary() { + ItemDictionary novaItemDictionary = Game.itemDictionary(); + + for (String oredictEntry : novaItemDictionary.keys()) { + for (Item oreValue : novaItemDictionary.get(oredictEntry)) { + OreDictionary.registerOre(oredictEntry, ItemConverter.instance().toNative(oreValue)); + } + } + + for (String oredictEntry : OreDictionary.getOreNames()) { + for (ItemStack oreValue : OreDictionary.getOres(oredictEntry)) { + Item novaItem = ItemConverter.instance().getNovaItem(oreValue); + if (!novaItemDictionary.get(oredictEntry).contains(novaItem)) { + novaItemDictionary.add(oredictEntry, novaItem); + } + } + } + + novaItemDictionary.whenEntryAdded(this::onEntryAdded); + novaItemDictionary.whenEntryRemoved(this::onEntryRemoved); + } + + private void onEntryAdded(Dictionary.AddEvent event) { + ItemStack nativeValue = ItemConverter.instance().toNative(event.value); + if (!OreDictionary.getOres(event.key).contains(nativeValue)) { + OreDictionary.registerOre(event.key, nativeValue); + } + } + + private void onEntryRemoved(Dictionary.RemoveEvent event) { + int id = OreDictionary.getOreID(event.key); + ItemStack itemStack = ItemConverter.instance().toNative(event.value); + ItemStack toRemove = null; + for (ItemStack oreDictItemStack : OreDictionary.getOres(event.key)) { + if (oreDictItemStack.getItem() == itemStack.getItem() && toRemove.getItemDamage() == oreDictItemStack.getItemDamage()) { + toRemove = oreDictItemStack; + } + } + + if (toRemove != null) { + OREDICT_CONTENTS.get(id).remove(toRemove); + } + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/backward/BWItem.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/backward/BWItem.java new file mode 100644 index 000000000..c9b7b9e92 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/backward/BWItem.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item.backward; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import nova.core.item.Item; +import nova.core.retention.Storable; + +/** + * @author Stan + * @since 3/02/2015. + */ +public class BWItem extends Item implements Storable { + private final net.minecraft.item.Item item; + private final int meta; + private final NBTTagCompound tag; + + public BWItem(ItemStack itemStack) { + this(itemStack.getItem(), itemStack.getHasSubtypes() ? itemStack.getItemDamage() : 0, itemStack.getTagCompound()); + } + + public BWItem(net.minecraft.item.Item item, int meta, NBTTagCompound tag) { + this.item = item; + this.meta = meta; + this.tag = tag; + } + + public net.minecraft.item.Item getItem() { + return item; + } + + public int getMeta() { + return meta; + } + + public NBTTagCompound getTag() { + return tag; + } + + public ItemStack makeItemStack(int stackSize) { + ItemStack result = new ItemStack(item, stackSize, meta); + if (tag != null) { + result.deserializeNBT(tag); + } + return result; + } + + @Override + public String toString() { + return getID(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/backward/BWItemFactory.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/backward/BWItemFactory.java new file mode 100644 index 000000000..6a39fd5bb --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/backward/BWItemFactory.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item.backward; + +import net.minecraft.nbt.NBTTagCompound; +import nova.core.component.misc.FactoryProvider; +import nova.core.item.Item; +import nova.core.item.ItemFactory; +import nova.core.retention.Data; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; +import nova.internal.core.Game; + +/** + * A Minecraft wrapped item factory. + * @author Stan + * @since 3/02/2015. + */ +public class BWItemFactory extends ItemFactory { + private final net.minecraft.item.Item item; + private final int meta; + + public BWItemFactory(net.minecraft.item.Item item, int meta) { + super(net.minecraft.item.Item.REGISTRY.getNameForObject(item) + (item.getHasSubtypes() ? ":" + meta : ""), () -> new BWItem(item, meta, null)); + + this.item = item; + this.meta = meta; + } + + public net.minecraft.item.Item getItem() { + return item; + } + + public int getMeta() { + return meta; + } + + @Override + public Item build(Data data) { + int meta = (Integer) data.getOrDefault("damage", this.meta); + NBTTagCompound nbtData = Game.natives().toNative(data); + BWItem bwItem = new BWItem(item, meta, nbtData); + bwItem.components.add(new FactoryProvider(this)); + WrapperEvent.BWItemCreate event = new WrapperEvent.BWItemCreate(bwItem, item); + Game.events().publish(event); + return bwItem; + } + + @Override + public Data save(Item item) { + if (!(item instanceof BWItem)) { + throw new IllegalArgumentException("This factory can only handle MCItems"); + } + + BWItem mcItem = (BWItem) item; + + Data result = mcItem.getTag() != null ? Game.natives().toNova(mcItem.getTag()) : new Data(); + if (result == null) { + result = new Data(); + } + + if (mcItem.getMeta() != meta) { + result.put("damage", mcItem.getMeta()); + } + + return result; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWItem.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWItem.java new file mode 100644 index 000000000..c0deadc88 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWItem.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward; + +import nova.core.wrapper.mc.forge.v1_11.wrapper.capability.forward.FWCapabilityProvider; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import nova.core.item.Item; +import nova.core.item.ItemFactory; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; + +import java.util.List; + +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.ItemWrapperMethods; +import nova.internal.core.Game; + +/** + * @author Calclavia + */ +public class FWItem extends net.minecraft.item.Item implements ItemWrapperMethods { + + public final ItemFactory itemFactory; + + public FWItem(ItemFactory item) { + this.itemFactory = item; + setUnlocalizedName(item.getID()); + setMaxStackSize(item.build().getMaxCount()); + } + + @Override + public ICapabilityProvider initCapabilities(ItemStack stack, NBTTagCompound nbt) { + Item item = Game.natives().toNova(stack); + WrapperEvent.FWItemInitCapabilities event = new WrapperEvent.FWItemInitCapabilities(item, new FWCapabilityProvider()); + return event.capabilityProvider.hasCapabilities() ? event.capabilityProvider : null; + } + + @Override + public ItemFactory getItemFactory() { + return itemFactory; + } + + @Override + public void addInformation(ItemStack itemStack, EntityPlayer player, List list, boolean p_77624_4_) { + ItemWrapperMethods.super.addInformation(itemStack, player, list, p_77624_4_); + } + + @Override + public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { + return ItemWrapperMethods.super.onItemUse(player.getHeldItem(hand), player, world, pos.getX(), pos.getY(), pos.getZ(), side.ordinal(), hitX, hitY, hitZ); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player) { + return ItemWrapperMethods.super.onItemRightClick(itemStack, world, player); + } + + @Override + public int getColorFromItemStack(ItemStack itemStack, int p_82790_2_) { + return ItemWrapperMethods.super.getColorFromItemStack(itemStack, p_82790_2_); + } + +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWItemBlock.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWItemBlock.java new file mode 100644 index 000000000..485de5912 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWItemBlock.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import nova.core.item.Item; +import nova.core.item.ItemFactory; +import nova.core.wrapper.mc.forge.v1_11.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11.wrapper.capability.forward.FWCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11.wrapper.item.ItemWrapperMethods; +import nova.internal.core.Game; + +import java.util.List; + +/** + * @author Calclavia + */ +public class FWItemBlock extends net.minecraft.item.ItemBlock implements ItemWrapperMethods { + + public FWItemBlock(FWBlock block) { + super(block); + } + + @Override + public ICapabilityProvider initCapabilities(ItemStack stack, NBTTagCompound nbt) { + Item item = Game.natives().toNova(stack); + WrapperEvent.FWItemInitCapabilities event = new WrapperEvent.FWItemInitCapabilities(item, new FWCapabilityProvider()); + return event.capabilityProvider.hasCapabilities() ? event.capabilityProvider : null; + } + + @Override + public ItemFactory getItemFactory() { + return ((FWBlock) block).dummy.getItemFactory(); + } + + @Override + public void addInformation(ItemStack itemStack, EntityPlayer player, List list, boolean p_77624_4_) { + ItemWrapperMethods.super.addInformation(itemStack, player, list, p_77624_4_); + } + + @Override + public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { + return ItemWrapperMethods.super.onItemUse(player.getHeldItem(hand), player, world, pos.getX(), pos.getY(), pos.getZ(), side.ordinal(), hitX, hitY, hitZ); + } + + @Override + public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player) { + return ItemWrapperMethods.super.onItemRightClick(itemStack, world, player); + } + + @Override + public int getColorFromItemStack(ItemStack itemStack, int p_82790_2_) { + return ItemWrapperMethods.super.getColorFromItemStack(itemStack, p_82790_2_); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWNBTTagCompound.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWNBTTagCompound.java new file mode 100644 index 000000000..133273097 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/item/forward/FWNBTTagCompound.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.item.forward; + +import net.minecraft.nbt.NBTTagCompound; +import nova.core.item.Item; + +/** + * A wrapped NBTTagCompound object that references the item instance + * @author Stan + * @since 3/02/2015. + */ +public class FWNBTTagCompound extends NBTTagCompound { + private final Item item; + + public FWNBTTagCompound(Item item) { + this.item = item; + } + + public Item getItem() { + return item; + } + + @Override + public NBTTagCompound copy() { + FWNBTTagCompound result = new FWNBTTagCompound(item); + getKeySet().forEach(s -> result.setTag((String) s, getTag((String) s).copy())); + return result; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/backward/BWParticle.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/backward/BWParticle.java new file mode 100644 index 000000000..ccd415fab --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/backward/BWParticle.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.particle.backward; + +import com.google.common.collect.HashBiMap; +import net.minecraft.client.particle.Barrier; +import net.minecraft.client.particle.IParticleFactory; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleBlockDust; +import net.minecraft.client.particle.ParticleBreaking; +import net.minecraft.client.particle.ParticleBubble; +import net.minecraft.client.particle.ParticleCloud; +import net.minecraft.client.particle.ParticleCrit; +import net.minecraft.client.particle.ParticleDigging; +import net.minecraft.client.particle.ParticleDragonBreath; +import net.minecraft.client.particle.ParticleDrip; +import net.minecraft.client.particle.ParticleEnchantmentTable; +import net.minecraft.client.particle.ParticleEndRod; +import net.minecraft.client.particle.ParticleExplosion; +import net.minecraft.client.particle.ParticleExplosionHuge; +import net.minecraft.client.particle.ParticleExplosionLarge; +import net.minecraft.client.particle.ParticleFallingDust; +import net.minecraft.client.particle.ParticleFirework; +import net.minecraft.client.particle.ParticleFlame; +import net.minecraft.client.particle.ParticleFootStep; +import net.minecraft.client.particle.ParticleHeart; +import net.minecraft.client.particle.ParticleLava; +import net.minecraft.client.particle.ParticleMobAppearance; +import net.minecraft.client.particle.ParticleNote; +import net.minecraft.client.particle.ParticlePortal; +import net.minecraft.client.particle.ParticleRain; +import net.minecraft.client.particle.ParticleRedstone; +import net.minecraft.client.particle.ParticleSmokeLarge; +import net.minecraft.client.particle.ParticleSmokeNormal; +import net.minecraft.client.particle.ParticleSnowShovel; +import net.minecraft.client.particle.ParticleSpell; +import net.minecraft.client.particle.ParticleSpit; +import net.minecraft.client.particle.ParticleSplash; +import net.minecraft.client.particle.ParticleSuspend; +import net.minecraft.client.particle.ParticleSuspendedTown; +import net.minecraft.client.particle.ParticleSweepAttack; +import net.minecraft.client.particle.ParticleTotem; +import net.minecraft.client.particle.ParticleWaterWake; +import net.minecraft.util.EnumParticleTypes; +import net.minecraftforge.fml.client.FMLClientHandler; + +import java.util.HashMap; +import java.util.Map; + +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.backward.BWEntity; +import nova.core.wrapper.mc.forge.v1_11.wrapper.particle.forward.MCParticleTransform; + +/** + * A backward entity particle that acts as a black box, which wraps a Minecraft particle. + * + * TODO: Minecraft particles are no longer entities. + * + * @author Calclavia + */ +public class BWParticle extends BWEntity { + + public static final HashBiMap> FX_CLASS_MAP = HashBiMap.create(); + public static final Map FX_FACTORY_MAP = new HashMap<>(); + + static { + //TODO: Handle duplicate fxs using a function instead of a map + FX_CLASS_MAP.put(EnumParticleTypes.EXPLOSION_NORMAL.getParticleID(), ParticleExplosion.class); + FX_CLASS_MAP.put(EnumParticleTypes.WATER_BUBBLE.getParticleID(), ParticleBubble.class); + FX_CLASS_MAP.put(EnumParticleTypes.WATER_SPLASH.getParticleID(), ParticleSplash.class); + FX_CLASS_MAP.put(EnumParticleTypes.WATER_WAKE.getParticleID(), ParticleWaterWake.class); + FX_CLASS_MAP.put(EnumParticleTypes.WATER_DROP.getParticleID(), ParticleRain.class); + FX_CLASS_MAP.put(EnumParticleTypes.SUSPENDED.getParticleID(), ParticleSuspend.class); + //FX_CLASS_MAP.put(EnumParticleTypes.SUSPENDED_DEPTH.getParticleID(), ParticleSuspendedTown.class); + FX_CLASS_MAP.put(EnumParticleTypes.CRIT.getParticleID(), ParticleCrit.class); + //FX_CLASS_MAP.put(EnumParticleTypes.CRIT_MAGIC.getParticleID(), ParticleCrit.class); + FX_CLASS_MAP.put(EnumParticleTypes.SMOKE_NORMAL.getParticleID(), ParticleSmokeNormal.class); + FX_CLASS_MAP.put(EnumParticleTypes.SMOKE_LARGE.getParticleID(), ParticleSmokeLarge.class); + FX_CLASS_MAP.put(EnumParticleTypes.SPELL.getParticleID(), ParticleSpell.class); + /*FX_CLASS_MAP.put(EnumParticleTypes.SPELL_INSTANT.getParticleID(), ParticleSpell.class); + FX_CLASS_MAP.put(EnumParticleTypes.SPELL_MOB.getParticleID(), ParticleSpell.class); + FX_CLASS_MAP.put(EnumParticleTypes.SPELL_MOB_AMBIENT.getParticleID(), ParticleSpell.class); + FX_CLASS_MAP.put(EnumParticleTypes.SPELL_WITCH.getParticleID(), ParticleSpell.class);*/ + FX_CLASS_MAP.put(EnumParticleTypes.DRIP_WATER.getParticleID(), ParticleDrip.class); + //FX_CLASS_MAP.put(EnumParticleTypes.DRIP_LAVA.getParticleID(), ParticleDrip.class); + //FX_CLASS_MAP.put(EnumParticleTypes.VILLAGER_ANGRY.getParticleID(), ParticleHeart.class); + //FX_CLASS_MAP.put(EnumParticleTypes.VILLAGER_HAPPY.getParticleID(), ParticleSuspendedTown.class); + FX_CLASS_MAP.put(EnumParticleTypes.TOWN_AURA.getParticleID(), ParticleSuspendedTown.class); + FX_CLASS_MAP.put(EnumParticleTypes.NOTE.getParticleID(), ParticleNote.class); + FX_CLASS_MAP.put(EnumParticleTypes.PORTAL.getParticleID(), ParticlePortal.class); + FX_CLASS_MAP.put(EnumParticleTypes.ENCHANTMENT_TABLE.getParticleID(), ParticleEnchantmentTable.class); + FX_CLASS_MAP.put(EnumParticleTypes.FLAME.getParticleID(), ParticleFlame.class); + FX_CLASS_MAP.put(EnumParticleTypes.LAVA.getParticleID(), ParticleLava.class); + FX_CLASS_MAP.put(EnumParticleTypes.FOOTSTEP.getParticleID(), ParticleFootStep.class); + FX_CLASS_MAP.put(EnumParticleTypes.CLOUD.getParticleID(), ParticleCloud.class); + FX_CLASS_MAP.put(EnumParticleTypes.REDSTONE.getParticleID(), ParticleRedstone.class); + FX_CLASS_MAP.put(EnumParticleTypes.SNOWBALL.getParticleID(), ParticleBreaking.class); + FX_CLASS_MAP.put(EnumParticleTypes.SNOW_SHOVEL.getParticleID(), ParticleSnowShovel.class); + //FX_CLASS_MAP.put(EnumParticleTypes.SLIME.getParticleID(), ParticleBreaking.class); + FX_CLASS_MAP.put(EnumParticleTypes.HEART.getParticleID(), ParticleHeart.class); + FX_CLASS_MAP.put(EnumParticleTypes.BARRIER.getParticleID(), Barrier.class); + //FX_CLASS_MAP.put(EnumParticleTypes.ITEM_CRACK.getParticleID(), ParticleBreaking.class); + FX_CLASS_MAP.put(EnumParticleTypes.BLOCK_CRACK.getParticleID(), ParticleDigging.class); + FX_CLASS_MAP.put(EnumParticleTypes.BLOCK_DUST.getParticleID(), ParticleBlockDust.class); + FX_CLASS_MAP.put(EnumParticleTypes.EXPLOSION_HUGE.getParticleID(), ParticleExplosionHuge.class); + FX_CLASS_MAP.put(EnumParticleTypes.EXPLOSION_LARGE.getParticleID(), ParticleExplosionLarge.class); + FX_CLASS_MAP.put(EnumParticleTypes.FIREWORKS_SPARK.getParticleID(), ParticleFirework.Spark.class); + FX_CLASS_MAP.put(EnumParticleTypes.MOB_APPEARANCE.getParticleID(), ParticleMobAppearance.class); + FX_CLASS_MAP.put(EnumParticleTypes.SPIT.getParticleID(), ParticleSpit.class); + FX_CLASS_MAP.put(EnumParticleTypes.FALLING_DUST.getParticleID(), ParticleFallingDust.class); + FX_CLASS_MAP.put(EnumParticleTypes.DRAGON_BREATH.getParticleID(), ParticleDragonBreath.class); + FX_CLASS_MAP.put(EnumParticleTypes.END_ROD.getParticleID(), ParticleEndRod.class); + /*FX_CLASS_MAP.put(EnumParticleTypes.DAMAGE_INDICATOR.getParticleID(), ParticleCrit.class);*/ + FX_CLASS_MAP.put(EnumParticleTypes.SWEEP_ATTACK.getParticleID(), ParticleSweepAttack.class); + FX_CLASS_MAP.put(EnumParticleTypes.TOTEM.getParticleID(), ParticleTotem.class); + + FX_FACTORY_MAP.put(EnumParticleTypes.EXPLOSION_NORMAL.getParticleID(), new ParticleExplosion.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.WATER_BUBBLE.getParticleID(), new ParticleBubble.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.WATER_SPLASH.getParticleID(), new ParticleSplash.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.WATER_WAKE.getParticleID(), new ParticleWaterWake.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.WATER_DROP.getParticleID(), new ParticleRain.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SUSPENDED.getParticleID(), new ParticleSuspend.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SUSPENDED_DEPTH.getParticleID(), new ParticleSuspendedTown.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.CRIT.getParticleID(), new ParticleCrit.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.CRIT_MAGIC.getParticleID(), new ParticleCrit.MagicFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SMOKE_NORMAL.getParticleID(), new ParticleSmokeNormal.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SMOKE_LARGE.getParticleID(), new ParticleSmokeLarge.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SPELL.getParticleID(), new ParticleSpell.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SPELL_INSTANT.getParticleID(), new ParticleSpell.InstantFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SPELL_MOB.getParticleID(), new ParticleSpell.MobFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SPELL_MOB_AMBIENT.getParticleID(), new ParticleSpell.AmbientMobFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SPELL_WITCH.getParticleID(), new ParticleSpell.WitchFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.DRIP_WATER.getParticleID(), new ParticleDrip.WaterFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.DRIP_LAVA.getParticleID(), new ParticleDrip.LavaFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.VILLAGER_ANGRY.getParticleID(), new ParticleHeart.AngryVillagerFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.VILLAGER_HAPPY.getParticleID(), new ParticleSuspendedTown.HappyVillagerFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.TOWN_AURA.getParticleID(), new ParticleSuspendedTown.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.NOTE.getParticleID(), new ParticleNote.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.PORTAL.getParticleID(), new ParticlePortal.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.ENCHANTMENT_TABLE.getParticleID(), new ParticleEnchantmentTable.EnchantmentTable()); + FX_FACTORY_MAP.put(EnumParticleTypes.FLAME.getParticleID(), new ParticleFlame.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.LAVA.getParticleID(), new ParticleLava.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.FOOTSTEP.getParticleID(), new ParticleFootStep.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.CLOUD.getParticleID(), new ParticleCloud.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.REDSTONE.getParticleID(), new ParticleRedstone.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SNOWBALL.getParticleID(), new ParticleBreaking.SnowballFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SNOW_SHOVEL.getParticleID(), new ParticleSnowShovel.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SLIME.getParticleID(), new ParticleBreaking.SlimeFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.HEART.getParticleID(), new ParticleHeart.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.BARRIER.getParticleID(), new Barrier.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.ITEM_CRACK.getParticleID(), new ParticleBreaking.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.BLOCK_CRACK.getParticleID(), new ParticleDigging.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.BLOCK_DUST.getParticleID(), new ParticleBlockDust.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.EXPLOSION_HUGE.getParticleID(), new ParticleExplosionHuge.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.EXPLOSION_LARGE.getParticleID(), new ParticleExplosionLarge.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.FIREWORKS_SPARK.getParticleID(), new ParticleFirework.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.MOB_APPEARANCE.getParticleID(), new ParticleMobAppearance.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SPIT.getParticleID(), new ParticleSpit.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.FALLING_DUST.getParticleID(), new ParticleFallingDust.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.DRAGON_BREATH.getParticleID(), new ParticleDragonBreath.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.END_ROD.getParticleID(), new ParticleEndRod.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.DAMAGE_INDICATOR.getParticleID(), new ParticleCrit.DamageIndicatorFactory()); + FX_FACTORY_MAP.put(EnumParticleTypes.SWEEP_ATTACK.getParticleID(), new ParticleSweepAttack.Factory()); + FX_FACTORY_MAP.put(EnumParticleTypes.TOTEM.getParticleID(), new ParticleTotem.Factory()); + } + + private final int particleID; + + public BWParticle(int particleID) { + //TODO: NPE + super(null); + this.particleID = particleID; + } + + public Particle createParticle(net.minecraft.world.World world) { + //Look up for particle factory and pass it into BWParticle + IParticleFactory particleFactory = (IParticleFactory) FMLClientHandler.instance().getClient().effectRenderer.particleTypes.get(particleID); + Particle particle = particleFactory.createParticle(0, world, 0, 0, 0, 0, 0, 0, 0); + if (components.has(MCParticleTransform.class)) + components.remove(MCParticleTransform.class); + components.add(new MCParticleTransform(particle)); + return particle; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/forward/FWParticle.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/forward/FWParticle.java new file mode 100644 index 000000000..702f1e77a --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/forward/FWParticle.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.particle.forward; + +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.world.World; +import net.minecraftforge.fml.client.FMLClientHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nova.core.block.Stateful; +import nova.core.component.Updater; +import nova.core.component.misc.Collider; +import nova.core.component.transform.EntityTransform; +import nova.core.entity.Entity; +import nova.core.entity.EntityFactory; +import nova.core.util.shape.Cuboid; +import nova.core.wrapper.mc.forge.v1_11.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11.wrapper.entity.forward.FWEntityRenderer; + +import static org.lwjgl.opengl.GL11.GL_QUADS; + +/** + * A copy of BWEntity that extends EntityFX + * @author Calclavia + */ +@SideOnly(Side.CLIENT) +public class FWParticle extends Particle { + + public final Entity wrapped; + public final EntityTransform transform; + + boolean firstTick = true; + + public FWParticle(World world, EntityFactory factory) { + super(world, 0, 0, 0); + this.wrapped = factory.build(); + this.transform = new MCParticleTransform(this); + wrapped.components.add(transform); + entityInit(); + } + + public FWParticle(World world, Entity entity) { + super(world, 0, 0, 0); + this.wrapped = entity; + this.transform = new MCParticleTransform(this); + wrapped.components.add(transform); + entityInit(); + } + + @Override + public void renderParticle(VertexBuffer worldRendererIn, net.minecraft.entity.Entity p_180434_2_, float p_70539_2_, float x, float y, float z, float p_70539_6_, float p_70539_7_) { + if (firstTick) { + prevPosX = posX; + prevPosY = posY; + prevPosZ = posZ; + setPosition(posX, posY, posZ); + firstTick = false; + } + float f11 = (float) (this.prevPosX + (this.posX - this.prevPosX) * (double) p_70539_2_ - interpPosX); + float f12 = (float) (this.prevPosY + (this.posY - this.prevPosY) * (double) p_70539_2_ - interpPosY); + float f13 = (float) (this.prevPosZ + (this.posZ - this.prevPosZ) * (double) p_70539_2_ - interpPosZ); + + Tessellator.getInstance().draw(); + FWEntityRenderer.render(this, wrapped, f11, f12, f13); + Tessellator.getInstance().getBuffer().begin(GL_QUADS, DefaultVertexFormats.BLOCK); + FMLClientHandler.instance().getClient().renderEngine.bindTexture(RenderUtility.particleResource); + } + + /** + * All methods below here are exactly the same between FWEntity and FWParticle. + * ***************************************************************************** + */ + protected void entityInit() { + //MC calls entityInit() before we finish wrapping, so this variable is required to check if wrapped exists. + if (wrapped != null) { + wrapped.events.publish(new Stateful.LoadEvent()); + prevPosX = posX; + prevPosY = posY; + prevPosZ = posZ; + setPosition(posX, posY, posZ); + } + } + + @Override + public void onUpdate() { + //TODO: Minecraft's collision is messed up (gets concurrent problems) + this.canCollide = false; + this.particleAge = 0; + super.onUpdate(); + double deltaTime = 0.05; + + if (wrapped instanceof Updater) { + ((Updater) wrapped).update(deltaTime); + } + + //Wrap entity collider + if (wrapped.components.has(Collider.class)) { + Collider collider = wrapped.components.get(Collider.class); + + //Transform cuboid based on entity. + Cuboid size = collider + .boundingBox + .get(); + // .scalarMultiply(transform.scale()); + + //Sadly Minecraft doesn't support rotated cuboids. And fixed x-z sizes. We take average.. + float width = (float) ((size.max.getX() - size.min.getX()) + (size.max.getZ() - size.min.getZ())) / 2; + float height = (float) (size.max.getY() - size.min.getY()); + setSize(width, height); + } + + /** + * Update all components in the entity. + */ + wrapped.components() + .stream() + .filter(component -> component instanceof Updater) + .forEach(component -> ((Updater) component).update(deltaTime)); + } + + @Override + public void setExpired() { + wrapped.events.publish(new Stateful.UnloadEvent()); + super.setExpired(); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/forward/MCParticleTransform.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/forward/MCParticleTransform.java new file mode 100644 index 000000000..061a08a24 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/particle/forward/MCParticleTransform.java @@ -0,0 +1,70 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package nova.core.wrapper.mc.forge.v1_11.wrapper.particle.forward; + +import net.minecraft.client.particle.Particle; +import nova.core.component.transform.EntityTransform; +import nova.core.util.math.RotationUtil; +import nova.core.util.math.Vector3DUtil; +import nova.core.world.World; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Rotation; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * Wraps Transform3d used in particle + * @author ExE Boss + */ +public class MCParticleTransform extends EntityTransform { + public final net.minecraft.client.particle.Particle wrapper; + + public MCParticleTransform(Particle wrapper) { + this.wrapper = wrapper; + this.setPivot(Vector3D.ZERO); + } + + @Override + public World world() { + return Game.natives().toNova(wrapper.world); + } + + @Override + public void setWorld(World world) { + + } + + @Override + public Vector3D position() { + return new Vector3D(wrapper.posX, wrapper.posY, wrapper.posZ); + } + + @Override + public void setPosition(Vector3D position) { + wrapper.setPosition(position.getX(), position.getY(), position.getZ()); + } + + @Override + public void setScale(Vector3D scale) { + // MC Particles only have one scale. + wrapper.particleScale = (float) ((scale.getX() + scale.getY() + scale.getZ()) / 3); + } + + @Override + public Vector3D scale() { + return new Vector3D(wrapper.particleScale, wrapper.particleScale, wrapper.particleScale); + } + + @Override + public Rotation rotation() { + // TODO: Calculate rotation so that it is always facing the camera. + return new Rotation(RotationUtil.DEFAULT_ORDER, 0, 0, 0); + } + + @Override + public void setRotation(Rotation rotation) { + // Particles can’t be rotated. + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWClientRenderManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWClientRenderManager.java new file mode 100644 index 000000000..f59c6bb00 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWClientRenderManager.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLLog; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nova.core.render.RenderException; +import nova.core.render.texture.Texture; +import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; +import org.apache.logging.log4j.Level; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +import java.util.Iterator; + +/** + * @author Calclavia + */ +public class BWClientRenderManager extends BWRenderManager { + @SideOnly(Side.CLIENT) + @Override + public Vector2D getDimension(Texture texture) { + ResourceLocation loc = toResourceLocation(texture); + + try { + ImageInputStream in = ImageIO.createImageInputStream(Minecraft.getMinecraft().getResourceManager().getResource(loc).getInputStream()); + Iterator readers = ImageIO.getImageReaders(in); + if (readers.hasNext()) { + ImageReader reader = readers.next(); + try { + reader.setInput(in); + return new Vector2D(reader.getWidth(0), reader.getHeight(0)); + } finally { + reader.dispose(); + } + } + } catch (Exception e) { + FMLLog.log("NOVA", Level.ERROR, new RenderException("Couldn't load texture " + texture.getPath(), e), + !texture.getResource().toLowerCase().equals(texture.getResource()) ? + "Minecraft doesn’t support textures with uppercase characters" : ""); + } + return new Vector2D(16, 16); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWModel.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWModel.java new file mode 100644 index 000000000..af26d076d --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWModel.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward; + +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.VertexBuffer; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.ResourceLocation; +import nova.core.render.model.MeshModel; +import nova.core.render.texture.EntityTexture; +import nova.core.render.texture.Texture; +import nova.core.wrapper.mc.forge.v1_11.render.RenderUtility; + +import java.util.Optional; + +/** + * BWModel for dynamic rendering + * @author Calclavia + */ +public class BWModel extends MeshModel { + + public void render() { + render(Optional.empty()); + } + + public void render(Optional entityRenderManager) { + Tessellator tessellator = Tessellator.getInstance(); + VertexBuffer worldRenderer = tessellator.getBuffer(); + worldRenderer.color(1F, 1F, 1F, 1F); + + /** + * Convert textures and UV into Minecraft equivalent. + */ + flatten().forEach( + model -> { + System.out.println(model); + if (model instanceof MeshModel) { + MeshModel meshModel = (MeshModel) model; + meshModel.faces.forEach(face -> { + System.out.println(face); + // TODO: See if this works, and possibly fix it + // Brightness is defined as: skyLight << 20 | blockLight << 4 + if (face.getBrightness() >= 0) { + worldRenderer.lightmap((int)(face.getBrightness() * (15 << 20)), (int)(face.getBrightness() * (11 << 4))); + //worldRenderer.setBrightness((int) (face.getBrightness() * (15 << 20 | 11 << 4))); + } else { + // Determine nearest adjacent block. + worldRenderer.lightmap(15 << 20, 11 << 4); + //worldRenderer.setBrightness(15 << 20 | 11 << 4); + } + + worldRenderer.normal((int) face.normal.getX(), (int) face.normal.getY(), (int) face.normal.getZ()); + + System.out.println(face.texture); + if (face.texture.isPresent()) { + if (entityRenderManager.isPresent() && face.texture.get() instanceof EntityTexture) { + //We're not working on an atlas, so just do... this. + Texture t = face.texture.get(); + entityRenderManager.get().renderEngine.bindTexture(new ResourceLocation(t.domain, "textures/entities/" + t.resource + ".png")); + face.vertices.forEach( + v -> { + worldRenderer.color(v.color.red(), v.color.green(), v.color.blue(), v.color.alpha()); + worldRenderer.tex(v.uv.getX(), v.uv.getY()); + worldRenderer.pos(v.vec.getX(), v.vec.getY(), v.vec.getZ()); + } + ); + } else { + Texture texture = face.texture.get(); + TextureAtlasSprite icon = RenderUtility.instance.getTexture(texture); + face.vertices.forEach( + v -> { + worldRenderer.color(v.color.red(), v.color.green(), v.color.blue(), v.color.alpha()); + if (icon != null) { + worldRenderer.tex(icon.getInterpolatedU(16 * v.uv.getX()), icon.getInterpolatedV(16 * v.uv.getY())); + worldRenderer.pos(v.vec.getX(), v.vec.getY(), v.vec.getZ()); + } else { + worldRenderer.tex(v.uv.getX(), v.uv.getY()); + worldRenderer.pos(v.vec.getX(), v.vec.getY(), v.vec.getZ()); + } + } + ); + } + } else { + face.vertices.forEach( + v -> { + worldRenderer.color(v.color.red(), v.color.green(), v.color.blue(), v.color.alpha()); + worldRenderer.pos(v.vec.getX(), v.vec.getY(), v.vec.getZ()); + } + ); + } + }); + } + //TODO: Handle BW Rendering + } + ); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWRenderManager.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWRenderManager.java new file mode 100644 index 000000000..c153ec597 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/backward/BWRenderManager.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward; + +import net.minecraft.util.ResourceLocation; +import nova.core.render.RenderManager; +import nova.core.render.texture.Texture; +import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; + +public class BWRenderManager extends RenderManager { + + public static ResourceLocation toResourceLocation(Texture texture) { + return new ResourceLocation(texture.domain, texture.getPath()); + } + + @Override + public Vector2D getDimension(Texture texture) { + return new Vector2D(16, 16); + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWEmptyModel.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWEmptyModel.java new file mode 100644 index 000000000..9c9d47e54 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWEmptyModel.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.render.forward; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.EnumFacing; + +import java.util.Collections; +import java.util.List; + +/** + * Generates a smart model based on a NOVA Model + * @author Calclavia + */ +public class FWEmptyModel extends FWSmartModel implements IBakedModel { + + @Override + public List getQuads(IBlockState state, EnumFacing side, long rand) { + return Collections.emptyList(); + } + + @Override + public TextureAtlasSprite getParticleTexture() { + return null; + } + + @Override + public ItemOverrideList getOverrides() { + return ItemOverrideList.NONE; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartBlockModel.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartBlockModel.java new file mode 100644 index 000000000..24c4da890 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartBlockModel.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.render.forward; + +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward.BWModel; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.block.model.ItemTransformVec3f; +import net.minecraft.util.EnumFacing; +import nova.core.block.Block; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.component.renderer.StaticRenderer; +import org.lwjgl.util.vector.Vector3f; + +import java.util.List; + +/** + * Generates a smart model based on a NOVA Model + * @author Calclavia + */ +public class FWSmartBlockModel extends FWSmartModel implements IBakedModel { + + private final Block block; + private final boolean isItem; + + public FWSmartBlockModel(Block block, boolean isDummy) { + super(); + this.block = block; + this.isItem = isDummy; + // Change the default transforms to the default full Block transforms + this.itemCameraTransforms = new ItemCameraTransforms( + new ItemTransformVec3f(new Vector3f(75, 225, 0), // Third Person (Left) + new Vector3f(0, 0.1875f, 0.03125f), new Vector3f(0.375f, 0.375f, 0.375f)), + new ItemTransformVec3f(new Vector3f(75, 45, 0), // Third Person (Right) + new Vector3f(0, 0.1875f, 0.03125f), new Vector3f(0.375f, 0.375f, 0.375f)), + new ItemTransformVec3f(new Vector3f(0, 225, 0), // First Person (Left) + new Vector3f(0, 0, 0), new Vector3f(0.4f, 0.4f, 0.4f)), + new ItemTransformVec3f(new Vector3f(0, 45, 0), // First Person (Right) + new Vector3f(0, 0, 0), new Vector3f(0.4f, 0.4f, 0.4f)), + ItemTransformVec3f.DEFAULT, // Head + new ItemTransformVec3f(new Vector3f(30, 225, 0), // Gui + new Vector3f(0, 0, 0), new Vector3f(0.625f, 0.625f, 0.625f)), + new ItemTransformVec3f(new Vector3f(0, 0, 0), // Ground + new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)), + new ItemTransformVec3f(new Vector3f(0, 0, 0), // Fixed + new Vector3f(0, 0, 0), new Vector3f(0, 0, 0))); + } + + @Override + public List getQuads(IBlockState state, EnumFacing side, long rand) { + BWModel model = new BWModel(); + model.matrix.translate(0.5, 0.5, 0.5); + + if (isItem) { + if (block.components.has(StaticRenderer.class)) { + StaticRenderer staticRenderer = block.components.get(StaticRenderer.class); + staticRenderer.onRender.accept(model); + } else if (block.components.has(DynamicRenderer.class)) { + DynamicRenderer dynamicRenderer = block.components.get(DynamicRenderer.class); + dynamicRenderer.onRender.accept(model); + } + } else { + StaticRenderer renderer = block.components.get(StaticRenderer.class); + renderer.onRender.accept(model); + } + + return modelToQuads(model); + } + + @Override + public ItemOverrideList getOverrides() { + return ItemOverrideList.NONE; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartItemModel.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartItemModel.java new file mode 100644 index 000000000..c1ced7d18 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartItemModel.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.render.forward; + +import nova.core.wrapper.mc.forge.v1_11.wrapper.render.backward.BWModel; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.block.model.ItemTransformVec3f; +import net.minecraft.util.EnumFacing; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.component.renderer.Renderer; +import nova.core.component.renderer.StaticRenderer; +import nova.core.item.Item; +import org.lwjgl.util.vector.Vector3f; + +import java.util.List; + +/** + * Generates a smart model based on a NOVA Model + * @author Calclavia + */ +public class FWSmartItemModel extends FWSmartModel implements IBakedModel { + + private final Item item; + + public FWSmartItemModel(Item item) { + super(); + this.item = item; + // Change the default transforms to the default Item transforms + this.itemCameraTransforms = new ItemCameraTransforms( + new ItemTransformVec3f(new Vector3f(-90, 0, 0), new Vector3f(0, 1, -3), new Vector3f(0.55f, 0.55f, 0.55f)), // Third Person + new ItemTransformVec3f(new Vector3f(-90, 0, 0), new Vector3f(0, 1, -3), new Vector3f(0.55f, 0.55f, 0.55f)), // Third Person + new ItemTransformVec3f(new Vector3f(0, -135, 25), new Vector3f(0, 4, 2), new Vector3f(1.7f, 1.7f, 1.7f)), // First Person + new ItemTransformVec3f(new Vector3f(0, -135, 25), new Vector3f(0, 4, 2), new Vector3f(1.7f, 1.7f, 1.7f)), // First Person + ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT, + ItemTransformVec3f.DEFAULT, ItemTransformVec3f.DEFAULT); + } + + @Override + public List getQuads(IBlockState state, EnumFacing side, long rand) { + BWModel model = new BWModel(); + model.matrix.translate(0.5, 0.5, 0.5); + + if (item.components.has(StaticRenderer.class)) { + StaticRenderer staticRenderer = item.components.get(StaticRenderer.class); + staticRenderer.onRender.accept(model); + } else if (item.components.has(DynamicRenderer.class)) { + DynamicRenderer dynamicRenderer = item.components.get(DynamicRenderer.class); + dynamicRenderer.onRender.accept(model); + } + + return modelToQuads(model); + } + + @Override + public boolean isGui3d() { + return item.components.has(Renderer.class); + } + + @Override + public ItemOverrideList getOverrides() { + return ItemOverrideList.NONE; + } +} diff --git a/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartModel.java b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartModel.java new file mode 100644 index 000000000..9b3307a81 --- /dev/null +++ b/minecraft/1.11/src/main/java/nova/core/wrapper/mc/forge/v1_11/wrapper/render/forward/FWSmartModel.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.wrapper.render.forward; + +import com.google.common.primitives.Ints; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.EnumFacing; +import nova.core.render.model.CustomModel; +import nova.core.render.model.MeshModel; +import nova.core.render.model.Model; +import nova.core.render.model.Vertex; +import nova.core.util.Direction; +import nova.core.wrapper.mc.forge.v1_11.render.RenderUtility; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Generates a smart model based on a NOVA Model + * @author Calclavia + */ +public abstract class FWSmartModel implements IBakedModel { + + protected final VertexFormat format; + // Default item transforms. Can be changed in subclasses. + protected ItemCameraTransforms itemCameraTransforms = ItemCameraTransforms.DEFAULT; + + public FWSmartModel() { + this.format = new VertexFormat(); + this.format.addElement(DefaultVertexFormats.POSITION_3F); + this.format.addElement(DefaultVertexFormats.COLOR_4UB); + this.format.addElement(DefaultVertexFormats.TEX_2F); + } + + public static int[] vertexToInts(Vertex vertex, TextureAtlasSprite texture) { + return new int[] { + Float.floatToRawIntBits((float) vertex.vec.getX()), + Float.floatToRawIntBits((float) vertex.vec.getY()), + Float.floatToRawIntBits((float) vertex.vec.getZ()), + vertex.color.rgba(), + Float.floatToRawIntBits(texture.getInterpolatedU(16 * vertex.uv.getX())), + Float.floatToRawIntBits(texture.getInterpolatedV(16 * vertex.uv.getY())), + }; + } + + protected List modelToQuads(Model modelIn) { + return modelIn + .flatten() + .stream() + .flatMap( + model -> { + if (model instanceof MeshModel) { + MeshModel meshModel = (MeshModel) model; + return meshModel.faces + .stream() + .map( + face -> { + TextureAtlasSprite texture = face.texture.map(RenderUtility.instance::getTexture) + .orElse(Minecraft.getMinecraft().getTextureMapBlocks().getMissingSprite()); + List vertexData = face.vertices + .stream() + .map(v -> vertexToInts(v, texture)) + .collect(Collectors.toList()); + + int[] data = Ints.concat(vertexData.toArray(new int[][] {})); + //TODO: The facing might be wrong + return new BakedQuad(data, -1, EnumFacing.values()[Direction.fromVector(face.normal).ordinal()], + getParticleTexture(), true, getFormat()); + } + ); + } + //TODO: Handle BW Rendering + return Stream.empty(); + } + ) + .collect(Collectors.toList()); + } + + public VertexFormat getFormat() { + return format; + } + + @Override + public boolean isAmbientOcclusion() { + return true; + } + + @Override + public boolean isGui3d() { + return true; + } + + @Override + public boolean isBuiltInRenderer() { + return false; + } + + @Override + public TextureAtlasSprite getParticleTexture() { + return null; + } + + @Override + @Deprecated + public ItemCameraTransforms getItemCameraTransforms() { + return itemCameraTransforms; + } +} diff --git a/minecraft/1.11/src/main/resources/META-INF/nova_at.cfg b/minecraft/1.11/src/main/resources/META-INF/nova_at.cfg new file mode 100644 index 000000000..8602ae65f --- /dev/null +++ b/minecraft/1.11/src/main/resources/META-INF/nova_at.cfg @@ -0,0 +1,30 @@ +# NOVA Access Transformer configuration file + +# Resource Pack +public net.minecraft.client.resources.AbstractResourcePack field_110597_b #resourcePackFile + +# Rendering +public net.minecraft.client.particle.ParticleManager field_178932_g # particleTypes +public net.minecraft.client.renderer.block.model.ModelBakery field_177608_m # itemModelGenerator +public net.minecraft.client.renderer.block.model.ModelBakery field_177606_o # MODEL_GENERATED +public net.minecraft.client.renderer.block.model.ModelBakery field_177609_j # textureMap +public net.minecraft.client.renderer.block.model.ModelBakery field_177599_g # sprites +public net.minecraft.client.renderer.block.model.ModelBakery func_177578_a(Lnet/minecraft/client/renderer/block/model/ModelBlock;Lnet/minecraft/client/renderer/block/model/ModelRotation;Z)Lnet/minecraft/client/renderer/block/model/IBakedModel; # models + +# Particles +public net.minecraft.client.particle.Particle field_187122_b # worldObj +public net.minecraft.client.particle.Particle field_187123_c # prevPosX +public net.minecraft.client.particle.Particle field_187124_d # prevPosY +public net.minecraft.client.particle.Particle field_187125_e # prevPosZ +public net.minecraft.client.particle.Particle field_187126_f # posX +public net.minecraft.client.particle.Particle field_187127_g # posY +public net.minecraft.client.particle.Particle field_187128_h # posZ +public net.minecraft.client.particle.Particle field_187129_i # motionX +public net.minecraft.client.particle.Particle field_187130_j # motionY +public net.minecraft.client.particle.Particle field_187131_k # motionZ +public net.minecraft.client.particle.Particle field_187132_l # isCollided +public net.minecraft.client.particle.Particle field_187133_m # isExpired +public net.minecraft.client.particle.Particle field_187134_n # width +public net.minecraft.client.particle.Particle field_187135_o # height +public net.minecraft.client.particle.Particle field_70544_f # particleScale +public net.minecraft.client.particle.Particle field_70545_g # particleGravity diff --git a/minecraft/1.11/src/main/resources/assets/nova/textures/NOVA.png b/minecraft/1.11/src/main/resources/assets/nova/textures/NOVA.png new file mode 100644 index 000000000..1f42e113c Binary files /dev/null and b/minecraft/1.11/src/main/resources/assets/nova/textures/NOVA.png differ diff --git a/minecraft/1.11/src/main/resources/assets/nova/textures/NOVA.svg b/minecraft/1.11/src/main/resources/assets/nova/textures/NOVA.svg new file mode 100644 index 000000000..2ff05fe43 --- /dev/null +++ b/minecraft/1.11/src/main/resources/assets/nova/textures/NOVA.svg @@ -0,0 +1,53 @@ + + + + + + + image/svg+xml + + + + + + + NOVA + + + + + + + + diff --git a/minecraft/1.11/src/main/resources/fmlbranding.properties b/minecraft/1.11/src/main/resources/fmlbranding.properties new file mode 100644 index 000000000..d0872c237 --- /dev/null +++ b/minecraft/1.11/src/main/resources/fmlbranding.properties @@ -0,0 +1 @@ +fmlbranding=NOVA 0.0.1-SNAPSHOT diff --git a/minecraft/1.11/src/main/resources/mcmod.info b/minecraft/1.11/src/main/resources/mcmod.info new file mode 100644 index 000000000..6b534e351 --- /dev/null +++ b/minecraft/1.11/src/main/resources/mcmod.info @@ -0,0 +1,21 @@ +{ + "modListVersion": 2, + "modList": [{ + "modid": "nova", + "name": "NOVA", + "description": "NOVA (Neatly Organized Voxel API) is a modding framework for voxel games.", + "version": "0.0.1", + "mcversion": "1.11", + "url": "https://novaapi.net/", + "updateUrl": "", + "authorList": [ "calclavia", "RX14", "AEnterprise", "magik6k", "Shadowfacts" ], + "credits": "Created by the NOVA Team.\nPorted to Minecraft 1.11 by: ExE Boss.", + "logoFile": "/assets/nova/textures/NOVA.png", + "screenshots": [], + "parent": "", + "requiredMods": [], + "dependencies": [], + "dependants": [], + "useDependencyInformation": true + }] +} diff --git a/minecraft/1.11/src/test/java/nova/core/wrapper/mc/forge/v1_11/launcher/NovaLauncherTest.java b/minecraft/1.11/src/test/java/nova/core/wrapper/mc/forge/v1_11/launcher/NovaLauncherTest.java new file mode 100644 index 000000000..b73dcc587 --- /dev/null +++ b/minecraft/1.11/src/test/java/nova/core/wrapper/mc/forge/v1_11/launcher/NovaLauncherTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015 NOVA, All rights reserved. + * This library is free software, licensed under GNU Lesser General Public License version 3 + * + * This file is part of NOVA. + * + * NOVA is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NOVA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11.launcher; + +import nova.core.wrapper.mc.forge.v1_11.depmodules.ClientModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.GameInfoModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.KeyModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.LanguageModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.RenderModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.SaveModule; +import nova.core.wrapper.mc.forge.v1_11.depmodules.TickerModule; +import nova.internal.core.Game; +import nova.internal.core.bootstrap.DependencyInjectionEntryPoint; +import nova.wrappertests.depmodules.FakeNetworkModule; +import org.junit.Test; +import se.jbee.inject.bootstrap.Bundle; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author rx14 + */ +public class NovaLauncherTest extends nova.wrappertests.NovaLauncherTest { + + @Override + public List> getModules() { + return Arrays.>asList( + ClientModule.class, + KeyModule.class, + LanguageModule.class, + FakeNetworkModule.class, //NetworkManager calls into FML code in the class instantiation, so we create a fake. + RenderModule.class, + SaveModule.class, + TickerModule.class, + GameInfoModule.class + ); + } + + @Override + @Test + public void testLaunching() { + doLaunchAssert(createLauncher()); + } + + @Override + @Test + public void testResolveGame() { + DependencyInjectionEntryPoint diep = new DependencyInjectionEntryPoint(); + + getModules().forEach(diep::install); + + Game game = diep.init(); + + assertThat(game).isNotNull(); + } +} diff --git a/minecraft/1.7/build.gradle b/minecraft/1.7/build.gradle index d54fad419..47a069022 100644 --- a/minecraft/1.7/build.gradle +++ b/minecraft/1.7/build.gradle @@ -27,6 +27,8 @@ jar { attributes 'FMLCorePluginContainsFMLMod': 'true' attributes 'FMLAT': 'nova_at.cfg' } + + from (sourceSets.main.resources) } task deobfJar(type: Jar) { diff --git a/minecraft/1.7/gradle.properties b/minecraft/1.7/gradle.properties index dd8f10841..a1a1710e1 100644 --- a/minecraft/1.7/gradle.properties +++ b/minecraft/1.7/gradle.properties @@ -2,6 +2,7 @@ group = nova.core minecraft.version = 1.7.10 forge.version = 10.13.4.1448-1.7.10 +forgeGradleVersion = 1.2-SNAPSHOT packaging = jar info.inceptionYear = 2015 diff --git a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/recipes/MCCraftingGrid.java b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/recipes/MCCraftingGrid.java index 34c893dda..01eb6f266 100644 --- a/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/recipes/MCCraftingGrid.java +++ b/minecraft/1.7/src/main/java/nova/core/wrapper/mc/forge/v17/recipes/MCCraftingGrid.java @@ -183,20 +183,20 @@ public boolean setStack(int x, int y, Optional stack) { //System.out.println("SetStack(" + x + ", " + y + ") " + stack); int ix = y * width + x; - if (!stack.equals(stacks[ix])) { - if (stack.isPresent()) { - inventory.setInventorySlotContents(ix, Game.natives().toNative(stack.get())); + if (stack.isPresent()) { + if (!stack.get().equals(stacks[ix])) { + inventory.setInventorySlotContents(ix, Game.natives().toNative(stack.get())); - if (stacks[ix] == null) { - numberOfStacks++; - } + if (stacks[ix] == null) { + numberOfStacks++; + } - stacks[ix] = stack.get(); - } else { - numberOfStacks--; - inventory.setInventorySlotContents(ix, null); - stacks[ix] = null; + stacks[ix] = stack.get(); } + } else { + numberOfStacks--; + inventory.setInventorySlotContents(ix, null); + stacks[ix] = null; } return true; @@ -206,21 +206,21 @@ public boolean setStack(int x, int y, Optional stack) { public boolean setStack(int i, Optional stack) { //System.out.println("SetStack(" + i + ") " + stack); - if (stack == null) { + if (stack.isPresent()) { if (stacks[i] == null) { - return true; + numberOfStacks++; } - numberOfStacks--; - inventory.setInventorySlotContents(i, null); - stacks[i] = null; + inventory.setInventorySlotContents(i, Game.natives().toNative(stack.get())); + stacks[i] = stack.get(); } else { if (stacks[i] == null) { - numberOfStacks++; + return true; } - inventory.setInventorySlotContents(i, Game.natives().toNative(stack.get())); - stacks[i] = stack.get(); + numberOfStacks--; + inventory.setInventorySlotContents(i, null); + stacks[i] = null; } return true; diff --git a/minecraft/1.8/gradle.properties b/minecraft/1.8/gradle.properties index 0298ba764..086b9c89c 100644 --- a/minecraft/1.8/gradle.properties +++ b/minecraft/1.8/gradle.properties @@ -2,6 +2,7 @@ group = nova.core minecraft.version = 1.8 forge.version = 11.14.3.1491 +forgeGradleVersion = 1.2-SNAPSHOT packaging = jar info.inceptionYear = 2015 diff --git a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/recipes/MCCraftingGrid.java b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/recipes/MCCraftingGrid.java index 64e9a8524..80ae84fce 100644 --- a/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/recipes/MCCraftingGrid.java +++ b/minecraft/1.8/src/main/java/nova/core/wrapper/mc/forge/v18/recipes/MCCraftingGrid.java @@ -183,8 +183,8 @@ public boolean setStack(int x, int y, Optional stack) { //System.out.println("SetStack(" + x + ", " + y + ") " + stack); int ix = y * width + x; - if (!stack.equals(stacks[ix])) { - if (stack.isPresent()) { + if (stack.isPresent()) { + if (!stack.get().equals(stacks[ix])) { inventory.setInventorySlotContents(ix, Game.natives().toNative(stack.get())); if (stacks[ix] == null) { @@ -192,11 +192,11 @@ public boolean setStack(int x, int y, Optional stack) { } stacks[ix] = stack.get(); - } else { - numberOfStacks--; - inventory.setInventorySlotContents(ix, null); - stacks[ix] = null; } + } else { + numberOfStacks--; + inventory.setInventorySlotContents(ix, null); + stacks[ix] = null; } return true; @@ -206,21 +206,21 @@ public boolean setStack(int x, int y, Optional stack) { public boolean setStack(int i, Optional stack) { //System.out.println("SetStack(" + i + ") " + stack); - if (stack == null) { + if (stack.isPresent()) { if (stacks[i] == null) { - return true; + numberOfStacks++; } - numberOfStacks--; - inventory.setInventorySlotContents(i, null); - stacks[i] = null; + inventory.setInventorySlotContents(i, Game.natives().toNative(stack.get())); + stacks[i] = stack.get(); } else { if (stacks[i] == null) { - numberOfStacks++; + return true; } - inventory.setInventorySlotContents(i, Game.natives().toNative(stack.get())); - stacks[i] = stack.get(); + numberOfStacks--; + inventory.setInventorySlotContents(i, null); + stacks[i] = null; } return true; diff --git a/minecraft/build.gradle b/minecraft/build.gradle index 2f4e0648d..905f27d09 100644 --- a/minecraft/build.gradle +++ b/minecraft/build.gradle @@ -1,16 +1,19 @@ -buildscript{ - repositories{ - mavenCentral() - maven { - name "forge" - url "http://files.minecraftforge.net/maven" +subprojects { + buildscript { + repositories { + mavenCentral() + maven { + name "forge" + url "http://files.minecraftforge.net/maven" + } + maven { + name "sonatype" + url "https://oss.sonatype.org/content/repositories/snapshots/" + } } - maven { - name "sonatype" - url "https://oss.sonatype.org/content/repositories/snapshots/" + dependencies { + // Minecraft 1.11 requires newer ForgeGradle, while 1.7 and 1.8 require older. + classpath 'net.minecraftforge.gradle:ForgeGradle:' + property('forgeGradleVersion') } } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT' - } } diff --git a/settings.gradle b/settings.gradle index 5880535a0..27fdae8ff 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ rootProject.name = 'NOVA-Core' +include "minecraft:1.11" include "minecraft:1.8" include "minecraft:1.7" diff --git a/src/main/java/nova/core/util/Identifiable.java b/src/main/java/nova/core/util/Identifiable.java index e98159e43..3fc6a1d34 100644 --- a/src/main/java/nova/core/util/Identifiable.java +++ b/src/main/java/nova/core/util/Identifiable.java @@ -38,7 +38,6 @@ public interface Identifiable { * @param other Identifiable to compare to * @return If the Identifiables are the same type */ - default boolean sameType(Identifiable other) { return getID().equals(other.getID()); }