diff --git a/minecraft/.gitignore b/minecraft/.gitignore index ef93a8127..24faaf7de 100644 --- a/minecraft/.gitignore +++ b/minecraft/.gitignore @@ -3,5 +3,6 @@ !/build.gradle !/.gitignore +!/1.11.2 !/1.8 !/1.7.10 diff --git a/minecraft/1.11.2/.gitignore b/minecraft/1.11.2/.gitignore new file mode 100644 index 000000000..85be317cb --- /dev/null +++ b/minecraft/1.11.2/.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.2/build.gradle b/minecraft/1.11.2/build.gradle new file mode 100644 index 000000000..e21d5efcb --- /dev/null +++ b/minecraft/1.11.2/build.gradle @@ -0,0 +1,143 @@ +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.2" +archivesBaseName = "NOVA-Core-Wrapper-MC1.11.2" + +configurations { + fatJar + compile.extendsFrom fatJar + // Exclude slf4j-log4j from tests (we use slf4j-simple) + testRuntime.exclude module: 'slf4j-log4j12' + testRuntime.exclude module: 'log4j-slf4j-impl' +} + +dependencies { + fatJar project(":") + fatJar 'org.apache.logging.log4j:log4j-slf4j-impl:2.0-beta9' + 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_2.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_2.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_2.NovaMinecraftCore' + attributes 'FMLCorePluginContainsFMLMod': 'true' + attributes 'FMLAT': 'nova_at.cfg' + } + classifier = 'fat' + + doLast { + reobfFatJar.execute() + } +} + +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_20170612' + 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_2.NovaMinecraftCore' +} + +runServer { + jvmArgs '-Dfml.coreMods.load=nova.core.wrapper.mc.forge.v1_11_2.NovaMinecraftCore' +} + +processResources { + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info', 'fmlbranding.properties' + expand 'version': project.version, 'mcversion': project.minecraft.version + } + + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info', 'fmlbranding.properties' + } +} diff --git a/minecraft/1.11.2/gradle.properties b/minecraft/1.11.2/gradle.properties new file mode 100644 index 000000000..6c3c1709c --- /dev/null +++ b/minecraft/1.11.2/gradle.properties @@ -0,0 +1,10 @@ +group = nova.core + +minecraft.version = 1.11.2 +forge.version = 13.20.1.2386 +forgeGradleVersion = 2.2-SNAPSHOT + +packaging = jar +info.inceptionYear = 2016 +info.description = The wrapper of the Nova API to the MinecraftForge 1.11.2 modding system. +info.organization.name = NOVA diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/NovaMinecraftCore.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/NovaMinecraftCore.java new file mode 100644 index 000000000..04f4eeb53 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2; + +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin.MCVersion; +import nova.core.wrapper.mc.forge.v1_11_2.asm.transformers.Transformers; + +import java.util.Map; + +@MCVersion(value = "1.11.2") +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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/NovaMinecraftPreloader.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/NovaMinecraftPreloader.java new file mode 100644 index 000000000..c89b891d8 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/NovaMinecraftPreloader.java @@ -0,0 +1,380 @@ +/* + * 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_2; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; +import net.minecraft.client.resources.AbstractResourcePack; +import net.minecraft.client.resources.FileResourcePack; +import net.minecraft.client.resources.FolderResourcePack; +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_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.assets.NovaFileResourcePack; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.assets.NovaFolderResourcePack; +import nova.core.wrapper.mc.forge.v1_11_2.util.ReflectionUtil; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.assets.NovaResourcePack; +import nova.internal.core.Game; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javax.json.Json; +import javax.json.stream.JsonGenerator; + +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; + public static List> novaResourcePacks = Collections.emptyList(); + + 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 + * + * @param pack The resource pack to generate the sound JSON for. + * @return The generated sound JSON. + */ + public static String generateSoundJSON(AbstractResourcePack pack) { + StringWriter sw = new StringWriter(); + try (JsonGenerator json = Json.createGenerator(sw);) { + json.writeStartObject(); + if (pack instanceof FileResourcePack) { + //For zip resource packs + try { + generateSoundJSON((FileResourcePack) pack, json); + } catch (Exception e) { + Error error = new ExceptionInInitializerError("Error generating fake sound JSON file."); + error.addSuppressed(e); + throw error; + } + } else if (pack instanceof FolderResourcePack) { + //For folder resource packs + generateSoundJSON((FolderResourcePack) pack, json); + } + json.writeEnd().flush(); + return sw.toString(); + } + } + + private static JsonGenerator generateSoundJSON(FileResourcePack pack, JsonGenerator json) throws IOException { + try (ZipFile zipFile = new ZipFile(pack.resourcePackFile)) { + for (String domain : pack.getResourceDomains()) { + //Load all sounds in the assets/domain/sounds/* + if (getZipEntryForResourcePack(pack, "assets/" + domain + "/sounds/") != null) { + String prefix = "assets/" + domain + "/sounds/"; + zipFile.stream() + .filter(e -> e.getName().toLowerCase().startsWith(prefix.toLowerCase()) && !e.getName().equalsIgnoreCase(prefix)) + .forEach(e -> { + String soundName = e.getName().replaceFirst(prefix, "").replaceFirst("\\.[^\\.]+$", ""); + if (soundName.contains("/")) + return; + + json.writeStartObject(soundName); + json.write("category", "ambient"); + json.writeStartArray("sounds"); + + if (e.isDirectory()) { + zipFile.stream() + .filter(e2 -> e2.getName().startsWith(prefix + soundName + "/") && !e2.isDirectory()) + .map(ZipEntry::getName) + .map(s -> s.replaceFirst(prefix + soundName + "/", "").replaceFirst("\\.[^\\.]+$", "")) + .forEach(s -> json.write(soundName + "/" + s)); + } else { + json.write(soundName); + } + json.writeEnd().writeEnd(); + }); + } + } + } + + return json; + } + + private static JsonGenerator generateSoundJSON(FolderResourcePack pack, JsonGenerator json) { + for (String domain : pack.getResourceDomains()) { + //Load all sounds in the assets/domain/sounds/* + File folder = getFileForResourcePack(pack, "assets/" + domain + "/sounds/"); + if (folder.exists()) { + for (File listedFile : folder.listFiles()) { + String soundName = listedFile.getName().replaceFirst("\\.[^\\.]+$", ""); + json.writeStartObject(soundName); + json.write("category", "ambient"); + json.writeStartArray("sounds"); + if (listedFile.isFile()) { + json.write(soundName); + } else if (listedFile.isDirectory()) { + for (File soundItemFile : listedFile.listFiles()) + json.write(soundName + "/" + soundItemFile.getName().replaceFirst("\\.[^\\.]+$", "")); + } + json.writeEnd().writeEnd(); + } + } + } + + return json; + } + + public static String generatePackMcmeta() { + StringWriter sw = new StringWriter(); + try (JsonGenerator json = Json.createGenerator(sw);) { + json.writeStartObject() // { + .writeStartObject("pack") // "pack": { + .write("description", "NOVA mod resource pack") // "description": "NOVA mod resource pack", + .write("pack_format", 3) // "pack_format": 3 // Required by 1.11+ + .writeEnd() // } + .writeEnd() // } + .flush(); + + return sw.toString(); + } + } + + public static ZipEntry getZipEntryForResourcePack(FileResourcePack pack, String path) throws IOException { + if (pack instanceof NovaFileResourcePack) { + Optional entry = ((NovaFileResourcePack) pack).findFileCaseInsensitive(path); + if (entry.isPresent()) + return entry.get(); + } + + try (ZipFile zf = new ZipFile(pack.resourcePackFile)) { + return zf.getEntry(path); + } + } + + public static File getFileForResourcePack(FolderResourcePack pack, String path) { + if (pack instanceof NovaFolderResourcePack) { + Optional file = ((NovaFolderResourcePack) pack).findFileCaseInsensitive(path); + if (file.isPresent()) + return file.get(); + } + + return new File(pack.resourcePackFile, path); + } + + @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); + @SuppressWarnings("unchecked") + Set classLoaderExceptions = (Set) setField.get(classLoader); + classLoaderExceptions.remove("org.apache."); + Game.logger().info("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); + newMods.stream().filter(mc -> NovaMinecraft.MOD_ID.equals(mc.getModId())).findFirst().ifPresent(nova -> md.parentMod = nova); + 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 NovaModContainer(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); + @SuppressWarnings("unchecked") + List packs = (List) resourcePackField.get(FMLClientHandler.instance()); + + Set addedPacks = new HashSet<>(); + List> novaPacks = new LinkedList<>(); + + 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); + NovaFileResourcePack pack = new NovaFileResourcePack(file, novaMod.id(), novaMod.domains()); + packs.add(pack); + novaPacks.add(pack); + Game.logger().info("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().replace('.', '/'); + 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); + NovaFolderResourcePack pack = new NovaFolderResourcePack(folderFile, novaMod.id(), novaMod.domains()); + packs.add(pack); + novaPacks.add(pack); + Game.logger().info("Registered NOVA folder resource pack: {}", folderFile.getAbsolutePath()); + } + }); + resourcePackField.set(FMLClientHandler.instance(), packs); + novaResourcePacks = new ArrayList<>(novaPacks); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * A fake NovaMod to inject into FML. + */ + private static class NovaModContainer extends DummyModContainer { + private final ModMetadata meta; + private final Class mod; + private File source = null; + + public NovaModContainer(ModMetadata meta, Class mod) { + super(meta); + this.meta = 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/StaticForwarder.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/StaticForwarder.java new file mode 100644 index 000000000..544b27f37 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/StaticForwarder.java @@ -0,0 +1,102 @@ +/* + * 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_2.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.block.Block; +import nova.core.component.misc.FactoryProvider; +import nova.core.event.BlockEvent; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.backward.BWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWTileLoader; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Objects; + +/** + * Static forwarder forwards injected methods. + * @author Calclavia + */ +public class StaticForwarder { + + private StaticForwarder() {} + + public static void chunkSetBlockEvent(Chunk chunk, BlockPos pos, IBlockState oldBlockState, IBlockState newBlockState) { + nova.core.world.World world = WorldConverter.instance().toNova(chunk.getWorld()); + Vector3D position = new Vector3D((chunk.x << 4) + pos.getX(), pos.getY(), (chunk.z << 4) + pos.getZ()); + Block oldBlockInstance; + Block newBlockInstance; + + if (oldBlockState.getBlock() instanceof FWBlock) { + oldBlockInstance = ((FWBlock) oldBlockState.getBlock()).getFactory().build(); + } else { + oldBlockInstance = new BWBlock(oldBlockState, world, position); + Game.blocks().get(Objects.toString(net.minecraft.block.Block.REGISTRY.getNameForObject(oldBlockState.getBlock()))) + .ifPresent(blockFactory -> oldBlockInstance.components.getOrAdd(new FactoryProvider(blockFactory))); + } + + if (newBlockState.getBlock() instanceof FWBlock) { + newBlockInstance = ((FWBlock) newBlockState.getBlock()).getFactory().build(); + } else { + newBlockInstance = new BWBlock(newBlockState, world, position); + Game.blocks().get(Objects.toString(net.minecraft.block.Block.REGISTRY.getNameForObject(newBlockState.getBlock()))) + .ifPresent(blockFactory -> newBlockInstance.components.getOrAdd(new FactoryProvider(blockFactory))); + } + + // Publish the event + Game.events().publish(new BlockEvent.Change(world, position, oldBlockInstance, newBlockInstance)); + } + + /** + * Used to inject forwarded TileEntites + * @param world The world to create the TileEntity in. + * @param data The TileEntity NBT tag compound + * @param clazz The TileEntity class + * @return The new TileEntity instance + * @throws Exception when an exception occurs + */ + 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(); + } + } + + /** + * Checks if the prefix is equal to the NOVA mod ID ("nova"). + * + * @param prefix The prefix to check + * @return If the prefix is equal to the NOVA mod ID ("nova"). + */ + public static boolean isNovaPrefix(String prefix) { + return NovaMinecraft.MOD_ID.equals(prefix); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ASMHelper.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ASMHelper.java new file mode 100644 index 000000000..d3903bf51 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ASMHelper.java @@ -0,0 +1,394 @@ +/* + * 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_2.asm.lib; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import net.minecraft.launchwrapper.LaunchClassLoader; +import nova.internal.core.Game; +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); + } + Game.logger().info("Injecting into {}\n{}", injector.method, 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.isEmpty()) { + throw new RuntimeException("Needle not found in Haystack: " + injector.method + "\n" + printInsnList(injector.needle)); + } + + for (AbstractInsnNode node : callNodes) { + if (injector.before) { + Game.logger().info("Injected before: {}", printInsn(node)); + method.instructions.insertBefore(node, cloneInsnList(injector.injection)); + } else { + Game.logger().info("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<>(tcblocks.size()); + 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<>(locals.size()); + 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); + @SuppressWarnings("unchecked") + 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); + @SuppressWarnings("unchecked") + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/CC_ClassWriter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/CC_ClassWriter.java new file mode 100644 index 000000000..ad30b23c6 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ClassHeirachyManager.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ClassHeirachyManager.java new file mode 100644 index 000000000..07980422b --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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 If the class extends the superclass + */ + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ComponentInjector.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ComponentInjector.java new file mode 100644 index 000000000..58641d1ca --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ComponentInjector.java @@ -0,0 +1,195 @@ +/* + * 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_2.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 nova.internal.core.Game; +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 The constructed type + * @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()); + Game.logger().info("{} {}", 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/InsnListPrinter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/InsnListPrinter.java new file mode 100644 index 000000000..42bb4fc52 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/InstructionComparator.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/InstructionComparator.java new file mode 100644 index 000000000..bde3b868e --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ObfMapping.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/ObfMapping.java new file mode 100644 index 000000000..b49b235f8 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/TemplateInjector.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/TemplateInjector.java new file mode 100644 index 000000000..d2910a48c --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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 The class node to inject into + * @return If the injection changed anything + */ + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/package-info.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/lib/package-info.java new file mode 100644 index 000000000..492b88b39 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.asm.lib; \ No newline at end of file diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/ChunkTransformer.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/ChunkTransformer.java new file mode 100644 index 000000000..b431daa8d --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/ChunkTransformer.java @@ -0,0 +1,78 @@ +/* + * 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_2.asm.transformers; + +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.ASMHelper; +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.ObfMapping; +import nova.internal.core.Game; +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) { + Game.logger().info("Transforming Chunk class for chunkModified event."); + + //obf name: func_177436_a + ObfMapping obfMap = new ObfMapping("auo", "a", "(Lco;Latl;)Latl;"); + ObfMapping deobfMap = new ObfMapping("net/minecraft/world/chunk/Chunk", "setBlockState", "(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;)Lnet/minecraft/block/state/IBlockState;"); + + MethodNode method = ASMHelper.findMethod(obfMap, cnode); + + if (method == null) { + Game.logger().warn("Lookup {} failed. You are probably in a deobf environment.", obfMap); + method = ASMHelper.findMethod(deobfMap, cnode); + + if (method == null) { + throw new IllegalStateException("[NOVA] Lookup " + deobfMap + " failed!"); + } + } + + Game.logger().info("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_2/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); + } + + Game.logger().info("Injected instruction to method: {}", method.name); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/IForgeRegistryEntryTransformer.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/IForgeRegistryEntryTransformer.java new file mode 100644 index 000000000..1f7883453 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/IForgeRegistryEntryTransformer.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017 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 Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NOVA. If not, see . + */ + +package nova.core.wrapper.mc.forge.v1_11_2.asm.transformers; + +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.ASMHelper; +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.ObfMapping; +import nova.internal.core.Game; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.util.TraceClassVisitor; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * @author ExE Boss + */ +public class IForgeRegistryEntryTransformer implements Transformer { + + @Override + public void transform(ClassNode cnode) { + Game.logger().info("Transforming IForgeRegistryEntry class for correct NOVA mod id mapping."); + + ObfMapping mapping = new ObfMapping("net/minecraftforge/fml/common/registry/IForgeRegistryEntry$Impl", "setRegistryName", "(Ljava/lang/String;)Lnet/minecraftforge/fml/common/registry/IForgeRegistryEntry;"); + MethodNode method = ASMHelper.findMethod(mapping, cnode); + + if (method == null) { + throw new IllegalStateException("[NOVA] Lookup " + mapping + " failed!"); + } + + Game.logger().info("Transforming method {}", method.name); + + InsnList list = new InsnList(); + list.add(new VarInsnNode(ALOAD, 5)); + list.add(new MethodInsnNode(INVOKESTATIC, "nova/core/wrapper/mc/forge/v1_11_2/asm/StaticForwarder", "isNovaPrefix", "(Ljava/lang/String;)Z", false)); + list.add(new JumpInsnNode(IFNE, (LabelNode) method.instructions.get(120))); + + method.instructions.insert(method.instructions.get(101), list); + + Game.logger().info("Injected instruction to method: {}", method.name); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/TileEntityTransformer.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/TileEntityTransformer.java new file mode 100644 index 000000000..91e826d8d --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/TileEntityTransformer.java @@ -0,0 +1,69 @@ +/* + * 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_2.asm.transformers; + +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.ASMHelper; +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.InstructionComparator; +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.ObfMapping; +import nova.internal.core.Game; +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) { + + Game.logger().info("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) { + Game.logger().warn("Lookup {} failed. You are probably in a deobf environment.", obfMap); + method = ASMHelper.findMethod(deobfMap, cnode); + + if (method == null) { + throw new IllegalStateException("[NOVA] Lookup " + deobfMap + " failed!"); + } + } + + Game.logger().info("Transforming method {}", method.name); + + ASMHelper.removeBlock(method.instructions, new InstructionComparator.InsnListSection(method.instructions, 30, 33)); + + 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_2/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(29), list); + + Game.logger().info("Injected instruction to method: {}", method.name); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/Transformer.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/Transformer.java new file mode 100644 index 000000000..cd3a07f69 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/Transformers.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/Transformers.java new file mode 100644 index 000000000..d750043a9 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/asm/transformers/Transformers.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_2.asm.transformers; + +import net.minecraft.launchwrapper.IClassTransformer; +import nova.core.wrapper.mc.forge.v1_11_2.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"); + registerTransformer(new IForgeRegistryEntryTransformer(), "net.minecraftforge.fml.common.registry.IForgeRegistryEntry$Impl"); + } + + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/ClientModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/ClientModule.java new file mode 100644 index 000000000..2a152c3f5 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.depmodules; + +import nova.core.game.ClientManager; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/ComponentModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/ComponentModule.java new file mode 100644 index 000000000..3cd1623f3 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.depmodules; + +import nova.core.entity.component.RigidBody; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/GameInfoModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/GameInfoModule.java new file mode 100644 index 000000000..96a9bdf73 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/KeyModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/KeyModule.java new file mode 100644 index 000000000..e808576d2 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.depmodules; + +import nova.core.game.InputManager; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/LanguageModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/LanguageModule.java new file mode 100644 index 000000000..454922996 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.depmodules; + +import nova.core.language.LanguageManager; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/NetworkModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/NetworkModule.java new file mode 100644 index 000000000..114ca1584 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.depmodules; + +import nova.core.network.NetworkManager; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/SaveModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/SaveModule.java new file mode 100644 index 000000000..981e7d0f2 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.depmodules; + +import nova.core.util.registry.RetentionManager; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/TickerModule.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/depmodules/TickerModule.java new file mode 100644 index 000000000..fc5c85fef --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ClientProxy.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ClientProxy.java new file mode 100644 index 000000000..d1f21d0e2 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ClientProxy.java @@ -0,0 +1,189 @@ +/* + * 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_2.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.minecraft.util.ResourceLocation; +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 net.minecraftforge.fml.common.ProgressManager; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import nova.core.entity.Entity; +import nova.core.entity.EntityFactory; +import nova.core.language.LanguageManager; +import nova.core.wrapper.mc.forge.v1_11_2.NovaMinecraftPreloader; +import nova.core.wrapper.mc.forge.v1_11_2.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWTileRenderer; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.FWEntityRenderer; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.FWItem; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.particle.backward.BWParticle; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.particle.forward.FWParticle; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; + +/** + * @author Calclavia + */ +public class ClientProxy extends CommonProxy { + @Override + public void preInit(FMLPreInitializationEvent evt) { + super.preInit(evt); + MinecraftForge.EVENT_BUS.register(RenderUtility.instance); + ClientRegistry.bindTileEntitySpecialRenderer(FWTile.class, FWTileRenderer.instance); + RenderUtility.instance.preInit(evt); + } + + @Override + public void init(FMLInitializationEvent evt) { + super.init(evt); + RenderingRegistry.registerEntityRenderingHandler(FWEntity.class, FWEntityRenderer.instance); + } + + @Override + public void loadLanguage(LanguageManager languageManager) { + super.loadLanguage(languageManager); + ProgressManager.ProgressBar progressBar = ProgressManager.push("Loading NOVA language files", + NovaMinecraftPreloader.novaResourcePacks.size() + 1); + FMLProgressBar fmlProgressBar = new FMLProgressBar(progressBar); + fmlProgressBar.step("nova"); + Minecraft.getMinecraft().getLanguageManager().getLanguages() + .stream() + .map(lang -> lang.getLanguageCode().replace('_', '-')) + .forEach(langName -> { + ResourceLocation location = new ResourceLocation("nova", langName + ".lang"); + try { + Minecraft.getMinecraft().getResourceManager().getAllResources(location).forEach(resource -> + loadLanguage(languageManager, location, langName, resource.getInputStream())); + } catch (IOException ex) { + } + }); + NovaMinecraftPreloader.novaResourcePacks.forEach(pack -> { + fmlProgressBar.step(pack.getID()); + pack.getLanguageFiles().stream().forEach(location -> { + String resourcePath = location.getResourcePath(); + String langName = resourcePath.substring(5, resourcePath.length() - 5); + try { + Minecraft.getMinecraft().getResourceManager().getAllResources(location).forEach(resource -> + loadLanguage(languageManager, location, langName, resource.getInputStream())); + } catch (IOException ex) { + } + }); + }); + fmlProgressBar.finish(); + ProgressManager.pop(progressBar); + } + + private void loadLanguage(LanguageManager languageManager, ResourceLocation location, String langName, InputStream stream) { + try { + Properties p = new Properties(); + p.load(stream); + p.entrySet().stream().forEach(e -> languageManager.register(langName, e.getKey().toString(), e.getValue().toString())); + } catch (IOException ex) { + } + } + + @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() && + Optional.ofNullable(FMLClientHandler.instance().getClient().getIntegratedServer()).map(is -> !is.getPublic()).orElse(true)) { + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/CommonProxy.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/CommonProxy.java new file mode 100644 index 000000000..d019ba281 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/CommonProxy.java @@ -0,0 +1,79 @@ +/* + * 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_2.launcher; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +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.language.LanguageManager; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWTileUpdater; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.FWItem; + +import java.util.Set; + +/** + * @author Calclavia + */ +public class CommonProxy implements ForgeLoadable { + @Override + public void preInit(FMLPreInitializationEvent evt) { + 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 loadLanguage(LanguageManager languageManager) {} + + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/FMLEventHandler.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/FMLEventHandler.java new file mode 100644 index 000000000..c1c38b432 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/FMLEventHandler.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_2.launcher; + +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import nova.core.event.PlayerEvent; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.EntityConverter; +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(EntityConverter.instance().toNova(evt.player))); + } + + @SubscribeEvent + public void playerLeave(net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent evt) { + Game.events().publish(new PlayerEvent.Leave(EntityConverter.instance().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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/FMLProgressBar.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/FMLProgressBar.java new file mode 100644 index 000000000..01f6a9450 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/FMLProgressBar.java @@ -0,0 +1,35 @@ +/* + * 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_2.launcher; + +import net.minecraftforge.fml.common.ProgressManager.ProgressBar; +import nova.core.util.AbstractProgressBar; + +/** + * Wrapper class for FML progress bar that is shown when Minecraft boots. + * + * @author ExE Boss + */ +public class FMLProgressBar extends 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ForgeEventHandler.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ForgeEventHandler.java new file mode 100644 index 000000000..b2b758d03 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ForgeEventHandler.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_2.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_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.EntityConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.internal.core.Game; + +/** + * @author Stan, Calclavia + */ +public class ForgeEventHandler { + + @SubscribeEvent + public void worldUnload(WorldEvent.Load evt) { + Game.events().publish(new nova.core.event.WorldEvent.Load(WorldConverter.instance().toNova(evt.getWorld()))); + } + + @SubscribeEvent + public void worldLoad(WorldEvent.Unload evt) { + Game.events().publish(new nova.core.event.WorldEvent.Unload(WorldConverter.instance().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) { + nova.core.event.PlayerEvent.Interact evt = new nova.core.event.PlayerEvent.Interact( + WorldConverter.instance().toNova(event.getWorld()), + VectorConverter.instance().toNova(event.getPos()), + EntityConverter.instance().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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ForgeLoadable.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ForgeLoadable.java new file mode 100644 index 000000000..f9fb607fa --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/ForgeLoadable.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 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_2.launcher; + +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +/** + * A mod interface implemented to receive FML mod loading event calls. + * + * @author ExE Boss + */ +// TODO Maybe replace with wrapper events. +public interface ForgeLoadable { + + default void preInit(FMLPreInitializationEvent event) { + } + + default void init(FMLInitializationEvent event) { + } + + default void postInit(FMLPostInitializationEvent event) { + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/NovaMinecraft.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/NovaMinecraft.java new file mode 100644 index 000000000..106b4cdcb --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/NovaMinecraft.java @@ -0,0 +1,287 @@ + +/* + * 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_2.launcher; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.Mod; +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.wrapper.mc.forge.v1_11_2.NovaMinecraftPreloader; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.ClientModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.ComponentModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.GameInfoModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.KeyModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.LanguageModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.NetworkModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.SaveModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.TickerModule; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.CategoryConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.assets.AssetConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.BlockConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.cuboid.CuboidConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.EntityConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.inventory.InventoryConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.OreDictionaryIntegration; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.MinecraftRecipeRegistry; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.RecipeConverter; +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.HashSet; +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.MOD_ID, name = NovaMinecraft.NAME, version = NovaMinecraftPreloader.VERSION, acceptableRemoteVersions = "*") +public class NovaMinecraft { + + public static final String MOD_ID = "nova"; + public static final String NAME = "NOVA"; + public static final String GAME_ID = "minecraft"; + + @SidedProxy(clientSide = "nova.core.wrapper.mc.forge.v1_11_2.launcher.ClientProxy", serverSide = "nova.core.wrapper.mc.forge.v1_11_2.launcher.CommonProxy") + public static CommonProxy proxy; + @Mod.Instance(MOD_ID) + public static NovaMinecraft instance; + private static NovaLauncher launcher; + @Mod.Metadata(MOD_ID) + private static ModMetadata modMetadata; + + private static Set nativeConverters; + private static Set novaWrappers = new HashSet<>(); + private static List novaModWrappers; + + public static void registerWrapper(ForgeLoadable wrapper) { + novaWrappers.add(wrapper); + } + + /** + * ORDER OF LOADING. + * + * 1. Native Loaders 2. Native Converters 3. Mods + * + * @param evt The Minecraft Forge Pre-Initialization event + */ + @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(ComponentModule.class); + + Set> modClasses = NovaMinecraftPreloader.modClasses; + + proxy.registerResourcePacks(modClasses); + launcher = new NovaLauncher(diep, modClasses); + + Game.inject(diep); + + /** + * Register native converters + */ + Game.natives().registerConverter(new DataConverter()); + 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()); + Game.natives().registerConverter(new CategoryConverter()); + Game.natives().registerConverter(new AssetConverter()); + Game.natives().registerConverter(new RecipeConverter()); + + /** + * 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); + novaModWrappers = launcher.getOrdererdMods().stream().filter(mod -> mod instanceof ForgeLoadable).map(mod -> (ForgeLoadable) mod).collect(Collectors.toList()); + novaWrappers.removeAll(novaModWrappers); + + /** + * Instantiate native loaders + */ + nativeConverters = Game.natives().getNativeConverters().stream().filter(n -> n instanceof ForgeLoadable).map(n -> (ForgeLoadable) n).collect(Collectors.toSet()); + nativeConverters.stream().forEachOrdered(loadable -> loadable.preInit(evt)); + + // 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.loadLanguage(Game.language()); + Game.language().init(); + Game.render().init(); + Game.blocks().init(); + Game.items().init(); + Game.entities().init(); + + //Load preInit + int size = novaModWrappers.size() + novaWrappers.size(); + if (size > 0) { + progressBar = ProgressManager.push("Pre-initializing NOVA wrappers", size); + FMLProgressBar fmlProgressBar = new FMLProgressBar(progressBar); + novaModWrappers.stream().forEachOrdered(wrapper -> { + fmlProgressBar.step(wrapper.getClass()); + wrapper.preInit(evt); + }); + novaWrappers.stream().forEachOrdered(wrapper -> { + fmlProgressBar.step(wrapper.getClass()); + wrapper.preInit(evt); + }); + fmlProgressBar.finish(); + ProgressManager.pop(progressBar); + } + + proxy.preInit(evt); + + /** + * Register event handlers + */ + MinecraftForge.EVENT_BUS.register(new ForgeEventHandler()); + MinecraftForge.EVENT_BUS.register(new FMLEventHandler()); + MinecraftForge.EVENT_BUS.register(Game.retention()); + } catch (Exception e) { + Game.logger().error("Error during preInit"); + e.printStackTrace(); + throw new InitializationException(e); + } + } + + @Mod.EventHandler + public void init(FMLInitializationEvent evt) { + try { + proxy.init(evt); + nativeConverters.stream().forEachOrdered(forgeLoadable -> forgeLoadable.init(evt)); + int size = novaModWrappers.size() + novaWrappers.size(); + if (size > 0) { + ProgressManager.ProgressBar progressBar = ProgressManager.push("Initializing NOVA wrappers", size); + FMLProgressBar fmlProgressBar = new FMLProgressBar(progressBar); + novaModWrappers.stream().forEachOrdered(wrapper -> { + fmlProgressBar.step(wrapper.getClass()); + wrapper.init(evt); + }); + novaWrappers.stream().forEachOrdered(wrapper -> { + fmlProgressBar.step(wrapper.getClass()); + wrapper.init(evt); + }); + fmlProgressBar.finish(); + ProgressManager.pop(progressBar); + } + } catch (Exception e) { + Game.logger().error("Error during init"); + e.printStackTrace(); + throw new InitializationException(e); + } + } + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent evt) { + try { + proxy.postInit(evt); + nativeConverters.stream().forEachOrdered(forgeLoadable -> forgeLoadable.postInit(evt)); + Game.recipes().init(); + int size = novaModWrappers.size() + novaWrappers.size(); + if (size > 0) { + ProgressManager.ProgressBar progressBar = ProgressManager.push("Post-initializing NOVA wrappers", size); + FMLProgressBar fmlProgressBar = new FMLProgressBar(progressBar); + novaModWrappers.stream().forEachOrdered(wrapper -> { + fmlProgressBar.step(wrapper.getClass()); + wrapper.postInit(evt); + }); + novaWrappers.stream().forEachOrdered(wrapper -> { + fmlProgressBar.step(wrapper.getClass()); + wrapper.postInit(evt); + }); + fmlProgressBar.finish(); + ProgressManager.pop(progressBar); + } + } catch (Exception e) { + Game.logger().error("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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/FWClientManager.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/FWClientManager.java new file mode 100644 index 000000000..b3b665bc3 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.manager; + +import net.minecraft.client.Minecraft; +import nova.core.entity.Entity; +import nova.core.game.ClientManager; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/MCRetentionManager.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/MCRetentionManager.java new file mode 100644 index 000000000..a3cdd0573 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.manager; + +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +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 net.minecraftforge.fml.server.FMLServerHandler; +import nova.core.retention.Data; +import nova.core.retention.Storable; +import nova.core.util.registry.RetentionManager; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter; +import nova.internal.core.Game; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +/** + * 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 lastSaveTime = 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, DataConverter.instance().toNative(saveMap)); + } + + @Override + public void load(String filename, Storable storable) { + NBTTagCompound nbt = loadFile(filename); + storable.load(DataConverter.instance().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().replaceFirst("\\.nbt$", ".tmp.nbt")); + + CompressedStreamTools.writeCompressed(data, new FileOutputStream(tempFile)); + + if (file.exists()) { + file.delete(); + } + + tempFile.renameTo(file); + return true; + } catch (Exception e) { + Game.logger().error("Failed to queueSave {}!", file.getName()); + e.printStackTrace(); + return false; + } + } + + public boolean saveFile(File saveDirectory, String filename, NBTTagCompound data) { + return saveFile(new File(saveDirectory, filename + ".nbt"), 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) { + Game.logger().error("Failed to load {}!", file.getName()); + 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 + ".nbt")); + } + + 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.nanoTime() - lastSaveTime > 2_000_000_000) { + lastSaveTime = System.nanoTime(); + saveAll(); + } + } + + @Override + public void init() { + + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/config/NovaGuiConfig.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/config/NovaGuiConfig.java new file mode 100644 index 000000000..86cdfae5d --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/config/NovaGuiFactory.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/config/NovaGuiFactory.java new file mode 100644 index 000000000..84cb09be4 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/manager/config/NovaGuiFactory.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_2.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 boolean hasConfigGui() { + return false; + } + + @Override + public GuiScreen createConfigGui(GuiScreen parentScreen) { + return null; + } + + @Override + @Deprecated + public Class mainConfigGuiClass() { + return NovaGuiConfig.class; + } + + @Override + public Set runtimeGuiCategories() { + return null; + } + + @Override + @Deprecated + public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) { + return null; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/MCPacket.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/MCPacket.java new file mode 100644 index 000000000..4e75e369b --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/discriminator/NovaPacket.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/discriminator/NovaPacket.java new file mode 100644 index 000000000..2a88a9fbb --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/discriminator/NovaPacket.java @@ -0,0 +1,75 @@ +/* + * 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_2.network.discriminator; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.entity.player.EntityPlayer; +import nova.core.network.handler.PacketHandler; +import nova.core.wrapper.mc.forge.v1_11_2.network.MCPacket; +import nova.core.wrapper.mc.forge.v1_11_2.network.netty.MCNetworkManager; +import nova.core.wrapper.mc.forge.v1_11_2.util.WrapUtility; +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(), WrapUtility.getNovaPlayer(player).get()); + //Set the ID of the packet + packet.setID(subId); + packetHandler.read(packet); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/discriminator/PacketAbstract.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/discriminator/PacketAbstract.java new file mode 100644 index 000000000..13e4acf21 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/discriminator/PacketPlayerItem.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/discriminator/PacketPlayerItem.java new file mode 100644 index 000000000..50c480a9f --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/netty/ChannelHandler.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/netty/ChannelHandler.java new file mode 100644 index 000000000..ec75a1e3c --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.network.discriminator.NovaPacket; +import nova.core.wrapper.mc.forge.v1_11_2.network.discriminator.PacketAbstract; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/netty/MCNetworkManager.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/netty/MCNetworkManager.java new file mode 100644 index 000000000..14da12f25 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.network.MCPacket; +import nova.core.wrapper.mc.forge.v1_11_2.network.discriminator.NovaPacket; +import nova.core.wrapper.mc.forge.v1_11_2.network.discriminator.PacketAbstract; +import nova.core.wrapper.mc.forge.v1_11_2.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.MOD_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 MOD_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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/netty/MCPacketHandler.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/network/netty/MCPacketHandler.java new file mode 100644 index 000000000..1b79afc79 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.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).player)); + break; + default: + break; + } + + } + +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/render/RenderUtility.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/render/RenderUtility.java new file mode 100644 index 000000000..2892d995c --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/render/RenderUtility.java @@ -0,0 +1,228 @@ +/* + * 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_2.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.ModelResourceLocation; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +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.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import nova.core.component.renderer.StaticRenderer; +import nova.core.item.ItemFactory; +import nova.core.render.texture.Texture; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.ForgeLoadable; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.assets.AssetConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.BlockConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.FWItem; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.IFWItem; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.render.forward.FWEmptyModel; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.render.forward.FWSmartBlockModel; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.render.forward.FWSmartItemModel; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashMap; + +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 implements ForgeLoadable { + + public static final ResourceLocation particleResource = new ResourceLocation("textures/particle/particles.png"); + + public static final RenderUtility instance = new RenderUtility(); + //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(Texture texture) { + if (textureMap.containsKey(texture)) { + return textureMap.get(texture); + } + + //Fallback to MC texture + return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(AssetConverter.instance().toNativeTexture(texture).toString()); + } + + /** + * 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)); + Game.render().entityTextures.forEach(t -> registerIcon(t, event)); + } + } + + public void registerIcon(Texture texture, TextureStitchEvent.Pre event) { + textureMap.put(texture, event.getMap().registerSprite(AssetConverter.instance().toNativeTexture(texture))); + } + + @SubscribeEvent + public void textureHook(TextureStitchEvent.Post event) { + Game.render().blockTextures.forEach(this::updateTexureDimensions); + Game.render().itemTextures.forEach(this::updateTexureDimensions); + Game.render().entityTextures.forEach(this::updateTexureDimensions); + } + + /** + * Update the texture dimensions for the given texture. + * @param texture The texture to update. + * @throws RuntimeException If the texture update fails. + * @see PR review + */ + private void updateTexureDimensions(Texture texture) { + // NOTE: This is the only way to update the `dimension` field without breaking anything. + // https://github.com/NOVA-Team/NOVA-Core/pull/265#discussion_r103739268 + try { + Field dimension = Texture.class.getDeclaredField("dimension"); + dimension.setAccessible(true); + TextureAtlasSprite icon = getTexture(texture); + dimension.set(texture, new Vector2D(icon.getIconWidth(), icon.getIconHeight())); + dimension.setAccessible(false); + } catch (Exception ex) { + throw new RuntimeException("Cannot set dimension of texture " + texture, ex); + } + } + + @SubscribeEvent + public void onModelBakeEvent(ModelBakeEvent event) { + //Register all blocks + Game.blocks().registry.forEach(blockFactory -> { + Object blockObj = BlockConverter.instance().toNative(blockFactory); + 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"); + ItemFactory itemFactory = ((IFWItem)itemFromBlock).getItemFactory(); + nova.core.item.Item dummy = itemFactory.build(); + if (block.dummy.components.has(StaticRenderer.class)) { + event.getModelRegistry().putObject(blockLocation, new FWSmartBlockModel(block.dummy)); + } else { + event.getModelRegistry().putObject(blockLocation, FWEmptyModel.INSTANCE); + } + event.getModelRegistry().putObject(itemLocation, new FWSmartBlockModel(block.dummy, dummy)); + } + }); + + //Register all items + Game.items().registry.forEach(itemFactory -> { + ItemStack stack = ItemConverter.instance().toNative(itemFactory); + Item itemObj = stack.getItem(); + if (itemObj instanceof FWItem) { + FWItem item = (FWItem) itemObj; + ResourceLocation objRL = Item.REGISTRY.getNameForObject(item); + ModelResourceLocation itemLocation = new ModelResourceLocation(objRL, "inventory"); + event.getModelRegistry().putObject(itemLocation, new FWSmartItemModel(item.getItemFactory().build())); + } + }); + } + + @Override + public void preInit(FMLPreInitializationEvent event) { + //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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/MCInputManager.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/MCInputManager.java new file mode 100644 index 000000000..90f3c8843 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/MCLanguageManager.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/MCLanguageManager.java new file mode 100644 index 000000000..12e36ea68 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/MCLanguageManager.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_2.util; + +import net.minecraftforge.fml.common.FMLCommonHandler; +import nova.core.language.LanguageManager; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.ForgeLoadable; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.NovaMinecraft; + +/** + * @author Calclavia + */ +public class MCLanguageManager extends LanguageManager implements ForgeLoadable { + + public MCLanguageManager() { + NovaMinecraft.registerWrapper(this); + } + + @Override + public String getCurrentLanguage() { + return FMLCommonHandler.instance().getCurrentLanguage().replace('_', '-'); + } + + @Override + @SuppressWarnings("deprecation") + public String translate(String key) { + String value = super.translate(key); + if (value.equals(key)) + value = net.minecraft.util.text.translation.I18n.translateToLocal(key); + return value; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/ModCreativeTab.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/ModCreativeTab.java new file mode 100644 index 000000000..974bead69 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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, (Item) null); + } + + @Override + public ItemStack getTabIconItem() { + return item; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/ObfuscationConstants.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/ObfuscationConstants.java new file mode 100644 index 000000000..baaa5f8c6 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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 = { "player", "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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/ReflectionUtil.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/ReflectionUtil.java new file mode 100644 index 000000000..64eebe236 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/ReflectionUtil.java @@ -0,0 +1,319 @@ +/* + * 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_2.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.NonNullList; +import net.minecraft.util.WeightedRandom; +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 nova.internal.core.Game; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 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 + */ +@SuppressWarnings("unchecked") +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) { + Game.logger().error("ReflectionUtil can't find SeedEntry", ex); + } + + SEEDENTRY_SEED = getField(forgeSeedEntry, "seed"); + + Constructor seedEntryConstructor = null; + + try { + seedEntryConstructor = Objects.requireNonNull(forgeSeedEntry, "SeedEntry class is null").getConstructor(ItemStack.class, int.class); + seedEntryConstructor.setAccessible(true); + } catch (NoSuchMethodException | SecurityException | NullPointerException ex) { + Game.logger().error("ReflectionUtil can't find SeedEntry constructor", 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"); + } + + @SuppressWarnings("deprecation") + public static Map getTranslations() { + return getPrivateObject( + getPrivateStaticObject(net.minecraft.util.text.translation.I18n.class, "localizedName", "field_74839_a"), + "languageList", + "field_74816_c"); + } + + public static List> getOreIdStacks() { + try { + return (List>) OREDICTIONARY_IDTOSTACK.get(null); + } catch (IllegalAccessException ex) { + Game.logger().error("ERROR - could not load ore dictionary stacks!"); + return null; + } + } + + public static List> getOreIdStacksUn() { + try { + return (List>) OREDICTIONARY_IDTOSTACKUN.get(null); + } catch (IllegalAccessException ex) { + Game.logger().error("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) { + Game.logger().error("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) { + Game.logger().error("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) { + Game.logger().error("could not get inventory eventhandler"); + return null; + } + } + + public static EntityPlayer getCraftingSlotPlayer(SlotCrafting slot) { + try { + return (EntityPlayer) SLOTCRAFTING_PLAYER.get(slot); + } catch (IllegalAccessException | NullPointerException ex) { + Game.logger().error("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) { + Game.logger().error("could not get string translator"); + return null; + } + } + + public static ItemStack getSeedEntrySeed(Object entry) { + try { + return (ItemStack) SEEDENTRY_SEED.get(entry); + } catch (IllegalAccessException ex) { + Game.logger().error("could not get SeedEntry seed", ex); + return null; + } + } + + public static void setCraftingRecipeList(List craftingRecipeList) { + if (!setPrivateObject( + CraftingManager.getInstance(), + craftingRecipeList, + ObfuscationConstants.CRAFTINGMANAGER_RECIPES)) { + Game.logger().error("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) { + Game.logger().error("could not construct SeedEntry"); + } catch (IllegalAccessException ex) { + Game.logger().error("could not construct SeedEntry"); + } catch (IllegalArgumentException ex) { + Game.logger().error("could not construct SeedEntry"); + } catch (InvocationTargetException ex) { + Game.logger().error("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; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/WrapUtility.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/WrapUtility.java new file mode 100644 index 000000000..b9b7b7c7e --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/WrapUtility.java @@ -0,0 +1,69 @@ +/* + * 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_2.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_2.wrapper.entity.EntityConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.backward.BWEntity; + +import java.util.Objects; +import java.util.Optional; +import javax.annotation.Nullable; + +/** + * Wrap utility methods. + * @author Calclavia + */ +public class WrapUtility { + + private WrapUtility() {} + + public static Optional getNovaPlayer(@Nullable EntityPlayer player) { + if (player == null) + return Optional.empty(); + return EntityConverter.instance().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: Implement FWEntityPlayer + return null; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/WrapperEvent.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/WrapperEvent.java new file mode 100644 index 000000000..7af5fd6a0 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/util/WrapperEvent.java @@ -0,0 +1,167 @@ +/* + * 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_2.util; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import nova.core.block.Block; +import nova.core.component.Component; +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_2.wrapper.block.backward.BWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWTile; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.FWCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.backward.BWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.backward.BWItem; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +/** + * 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; + } + } + + public static class CapabilityToComponent extends Event { + public final ICapabilityProvider capabilities; + public final Class component; + public final Set defaultInstances; + public final Set instances; + public final Direction direction; + + public CapabilityToComponent(ICapabilityProvider capabilities, Class component, Set defaultInstances, Direction direction) { + this.capabilities = capabilities; + this.component = component; + this.defaultInstances = Collections.unmodifiableSet(defaultInstances); + this.instances = new HashSet<>(); + this.direction = direction; + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/CategoryConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/CategoryConverter.java new file mode 100644 index 000000000..bb01a118e --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/CategoryConverter.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017 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_2.wrapper; + +import net.minecraft.block.Block; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import nova.core.component.Category; +import nova.core.nativewrapper.NativeConverter; +import nova.core.wrapper.mc.forge.v1_11_2.util.ModCreativeTab; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.internal.core.Game; + +import java.util.Arrays; + +/** + * Converts NOVA {@link Category Categories} to Minecraft {@link CreativeTabs} and back. + * + * @author ExE Boss + */ +public class CategoryConverter implements NativeConverter{ + + public static CategoryConverter instance() { + return Game.natives().getNative(Category.class, CreativeTabs.class); + } + + @Override + public Class getNovaSide() { + return Category.class; + } + + @Override + public Class getNativeSide() { + return CreativeTabs.class; + } + + @Override + public Category toNova(CreativeTabs creativeTab) { + switch (creativeTab.getTabLabel()) { + case "buildingBlocks": + return Category.BUILDING_BLOCKS; + case "decorations": + return Category.DECORATIONS; + case "redstone": + return Category.TECHNOLOGY; + case "transportation": + return Category.TRANSPORTATION; + case "food": + return Category.FOOD; + case "tools": + return Category.TOOLS; + case "combat": + return Category.COMBAT; + case "brewing": + return Category.ALCHEMY; + case "materials": + return Category.MATERIALS; + case "misc": + return Category.MISCELLANEOUS; + default: + return new Category(creativeTab.getTabLabel(), ItemConverter.instance().toNova(creativeTab.getIconItemStack())); + } + } + + @Override + public CreativeTabs toNative(Category category) { + return toNative(category, ItemStack.EMPTY); + } + + public CreativeTabs toNative(Category category, Block block) { + return toNative(category, new ItemStack(block)); + } + + public CreativeTabs toNative(Category category, Item item) { + return toNative(category, new ItemStack(item)); + } + + public CreativeTabs toNative(Category category, ItemStack item) { + if (category.name.startsWith("nova:")) { + switch (category.name) { + case Category.BUILDING_BLOCKS_NAME: + return CreativeTabs.BUILDING_BLOCKS; + case Category.DECORATIONS_NAME: + return CreativeTabs.DECORATIONS; + case Category.TECHNOLOGY_NAME: + return CreativeTabs.REDSTONE; + case Category.TRANSPORTATION_NAME: + return CreativeTabs.TRANSPORTATION; + case Category.FOOD_NAME: + return CreativeTabs.FOOD; + case Category.TOOLS_NAME: + return CreativeTabs.TOOLS; + case Category.COMBAT_NAME: + return CreativeTabs.COMBAT; + case Category.ALCHEMY_NAME: + return CreativeTabs.BREWING; + case Category.MATERIALS_NAME: + return CreativeTabs.MATERIALS; + case Category.MISCELLANEOUS_NAME: + return CreativeTabs.MISC; + } + } + return Arrays.stream(CreativeTabs.CREATIVE_TAB_ARRAY) + .filter(tab -> tab.getTabLabel().equals(category.name)) + .findFirst() + .orElseGet(() -> new ModCreativeTab(category.name, category.item.map(ItemConverter.instance()::toNative).orElse(item))); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/DirectionConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/DirectionConverter.java new file mode 100644 index 000000000..38555635c --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/DirectionConverter.java @@ -0,0 +1,64 @@ +/* + * 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_2.wrapper; + +import net.minecraft.util.EnumFacing; +import nova.core.nativewrapper.NativeConverter; +import nova.core.util.Direction; +import nova.internal.core.Game; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * + * @author ExE Boss + */ +public class DirectionConverter implements NativeConverter { + + public static DirectionConverter instance() { + return Game.natives().getNative(Direction.class, EnumFacing.class); + } + + @Override + public Class getNovaSide() { + return Direction.class; + } + + @Override + public Class getNativeSide() { + return EnumFacing.class; + } + + @Override + public Direction toNova(@Nullable EnumFacing facing) { + if (null == facing) + return Direction.UNKNOWN; + else switch (facing) { + 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 + @Nullable + public EnumFacing toNative(Direction direction) { + switch (direction) { + 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 null; + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/VectorConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/VectorConverter.java new file mode 100644 index 000000000..9dfc195d7 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/VectorConverter.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_2.wrapper; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import nova.core.nativewrapper.NativeConverter; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +public class VectorConverter implements NativeConverter { + + public static VectorConverter instance() { + return Game.natives().getNative(Vector3D.class, BlockPos.class); + } + + @Override + public Class getNovaSide() { + return Vector3D.class; + } + + @Override + public Class getNativeSide() { + return BlockPos.class; + } + + public Vector3D toNova(Vec3d pos) { + return new Vector3D(pos.x, pos.y, pos.z); + } + + @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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/AssetConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/AssetConverter.java new file mode 100644 index 000000000..6c6b3f057 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/AssetConverter.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017 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_2.wrapper.assets; + +import net.minecraft.util.ResourceLocation; +import nova.core.nativewrapper.NativeConverter; +import nova.core.render.texture.Texture; +import nova.core.util.Asset; +import nova.internal.core.Game; + +/** + * @author ExE Boss + */ +public final class AssetConverter implements NativeConverter { + + public static AssetConverter instance() { + return Game.natives().getNative(Asset.class, ResourceLocation.class); + } + + @Override + public Class getNovaSide() { + return Asset.class; + } + + @Override + public Class getNativeSide() { + return ResourceLocation.class; + } + + @Override + public Asset toNova(ResourceLocation resource) { + return new Asset(resource.getResourceDomain(), resource.getResourcePath()) {}; + } + + public Texture toNovaTexture(ResourceLocation resource) { + return new Texture(resource.getResourceDomain(), resource.getResourcePath()); + } + + @Override + public ResourceLocation toNative(Asset asset) { + return new ResourceLocation(asset.domain.toLowerCase(), asset.name.toLowerCase());//path()); + } + + public ResourceLocation toNativeTexture(Asset asset) { + return toNativeTexture(asset, false); + } + + public ResourceLocation toNativeTexture(Asset asset, boolean preserveExtension) { + if (asset instanceof Texture) + return new ResourceLocation(asset.domain.toLowerCase(), asset.path().replaceFirst("^textures/", "").replaceFirst("\\.(\\w+)$", preserveExtension ? ".$1" : "")); + return new ResourceLocation(asset.domain.toLowerCase(), asset.path()); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaFileResourcePack.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaFileResourcePack.java new file mode 100644 index 000000000..67e6ed296 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaFileResourcePack.java @@ -0,0 +1,159 @@ +/* + * 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_2.wrapper.assets; + +import com.google.common.base.Charsets; +import net.minecraft.client.resources.FileResourcePack; +import net.minecraft.util.ResourceLocation; +import nova.core.language.LanguageManager; +import nova.core.wrapper.mc.forge.v1_11_2.NovaMinecraftPreloader; +import nova.internal.core.Game; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class NovaFileResourcePack extends FileResourcePack implements NovaResourcePack { + private final String modid; + private final String[] domains; + private ZipFile resourcePackZipFile; + + public NovaFileResourcePack(File file, String modid, String[] domains) { + super(file); + this.modid = modid; + this.domains = domains; + } + + private ZipFile getResourcePackZipFile() throws IOException { + if (this.resourcePackZipFile == null) { + this.resourcePackZipFile = new ZipFile(this.resourcePackFile); + } + + return this.resourcePackZipFile; + } + + @Override + public Set getResourceDomains() { + HashSet domains = new HashSet<>(); + domains.add(modid); + domains.addAll(Arrays.asList(this.domains)); + return domains; + } + + @Override + protected InputStream getInputStreamByName(String path) throws IOException { + path = transform(path); + try { + return getInputStreamCaseInsensitive(path); + } catch (IOException e) { + if (path.endsWith("sounds.json")) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generateSoundJSON(this).getBytes(Charsets.UTF_8)); + } else if ("pack.mcmeta".equalsIgnoreCase(path)) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generatePackMcmeta().getBytes(Charsets.UTF_8)); + } else { + if (path.endsWith(".mcmeta")) { + return new ByteArrayInputStream("{}".getBytes()); + } + throw e; + } + } + } + + @Override + public InputStream getInputStream(ResourceLocation rl) throws IOException { + return getInputStreamByName(transform(rl)); + } + + @Override + public boolean hasResourceName(String path) { + path = transform(path); + //Hack Sounds and McMeta + if (path.endsWith("sounds.json") || path.endsWith("pack.mcmeta")) { + return true; + } + + return findFileCaseInsensitive(path).isPresent(); + } + + @Override + public boolean resourceExists(ResourceLocation rl) { + //Hack Sounds and McMeta + if (rl.getResourcePath().endsWith("sounds.json") || rl.getResourcePath().endsWith("pack.mcmeta")) { + return true; + } + + return findFileCaseInsensitive(transform(rl)).isPresent(); + } + + @Override + public Set getLanguageFiles() { + Pattern langPattern = Pattern.compile("^assets/([^/]+)/(lang/[a-zA-Z0-9-]+\\.lang)$", Pattern.CASE_INSENSITIVE); + + try { + return getResourcePackZipFile().stream() + .map(e -> { + Matcher m = langPattern.matcher(e.getName()); + if (!m.matches()) + return null; + return new ResourceLocation(m.group(1), m.group(2)); + }) + .filter(e -> e != null) + .collect(Collectors.toSet()); + } catch (IOException ex) { + return Collections.emptySet(); + } + } + + @Override + public String getID() { + return modid; + } + + @Override + public InputStream getInputStreamCaseInsensitive(String path) throws IOException { + Optional ze = findFileCaseInsensitive(transform(path)); + if (ze.isPresent()) + return getResourcePackZipFile().getInputStream(ze.get()); + return super.getInputStreamByName(path); + } + + @Override + public Optional findFileCaseInsensitive(String path) { + String p = transform(path); + try { + return getResourcePackZipFile().stream().filter(e -> e.getName().equalsIgnoreCase(p)).findFirst().map(e -> (ZipEntry) e); + } catch (IOException ex) { + return Optional.empty(); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaFolderResourcePack.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaFolderResourcePack.java new file mode 100644 index 000000000..641575e65 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaFolderResourcePack.java @@ -0,0 +1,152 @@ +/* + * 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_2.wrapper.assets; + +import com.google.common.base.Charsets; +import net.minecraft.client.resources.FolderResourcePack; +import net.minecraft.util.ResourceLocation; +import nova.core.language.LanguageManager; +import nova.core.wrapper.mc.forge.v1_11_2.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.Optional; +import java.util.Properties; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class NovaFolderResourcePack extends FolderResourcePack implements NovaResourcePack { + 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; + } + + @Override + protected InputStream getInputStreamByName(String path) throws IOException { + path = transform(path); + try { + return getInputStreamCaseInsensitive(path); + } catch (IOException e) { + if (path.endsWith("sounds.json")) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generateSoundJSON(this).getBytes(Charsets.UTF_8)); + } else if ("pack.mcmeta".equalsIgnoreCase(path)) { + return new ByteArrayInputStream(NovaMinecraftPreloader.generatePackMcmeta().getBytes(Charsets.UTF_8)); + } else { + if (path.endsWith(".mcmeta")) { + return new ByteArrayInputStream("{}".getBytes()); + } + throw e; + } + } + } + + @Override + public InputStream getInputStream(ResourceLocation rl) throws IOException { + return getInputStreamByName(transform(rl)); + } + + @Override + public boolean hasResourceName(String path) { + path = transform(path); + //Hack Sounds and McMeta + if (path.endsWith("sounds.json") || path.endsWith("pack.mcmeta")) { + return true; + } + + return findFileCaseInsensitive(path).isPresent(); + } + + @Override + public boolean resourceExists(ResourceLocation rl) { + //Hack Sounds and McMeta + if (rl.getResourcePath().endsWith("sounds.json") || rl.getResourcePath().endsWith("pack.mcmeta")) { + return true; + } + + return findFileCaseInsensitive(transform(rl)).isPresent(); + } + + @Override + public Set getLanguageFiles() { + Pattern langPattern = Pattern.compile("^[a-zA-Z0-9-]+\\.lang$", Pattern.CASE_INSENSITIVE); + + Set langFiles = new HashSet<>(); + + for (String domain : getResourceDomains()) { + findFileCaseInsensitive("assets/" + domain + "/lang/").filter(File::isDirectory).ifPresent(file -> { + Arrays.stream(file.listFiles((dir, name) -> langPattern.asPredicate().test(name))) + .map(File::getName) + .forEach(name -> langFiles.add(new ResourceLocation(domain, name))); + }); + } + + return langFiles; + } + + @Override + public String getID() { + return modid; + } + + @Override + public InputStream getInputStreamCaseInsensitive(String path) throws IOException { + Optional file = findFileCaseInsensitive(transform(path)); + if (file.isPresent()) + return new FileInputStream(file.get()); + return super.getInputStreamByName(path); + } + + @Override + public Optional findFileCaseInsensitive(String path) { + final String transformedPath = transform(path); + + File[] files = resourcePackFile.listFiles((dir, name) -> transform(name).equalsIgnoreCase(transformedPath)); + + switch (files.length) { + case 0: + return Optional.empty(); + case 1: + return Optional.of(files[0]); + default: + // We are on a case sensitive file system + return Optional.of(new File(resourcePackFile, path)).filter(File::exists); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaResourcePack.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaResourcePack.java new file mode 100644 index 000000000..c655fe851 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/assets/NovaResourcePack.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2017 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_2.wrapper.assets; + +import net.minecraft.client.resources.IResourcePack; +import net.minecraft.util.ResourceLocation; +import nova.core.util.Identifiable; + +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedList; +import java.util.Optional; +import java.util.Set; + +/** + * @author ExE Boss + */ +public interface NovaResourcePack extends Identifiable, IResourcePack { + + default String transform(ResourceLocation rl) { + return transform(String.format("assets/%s/%s", rl.getResourceDomain(), toAbsolutePath(rl.getResourcePath()))); + } + + default String transform(String path) { + return toAbsolutePath(path.toLowerCase().replace('\\', '/').replaceFirst("^assets/minecraft", "assets/" + getID())); + } + + @Override + default String getPackName() { + return getClass().getSimpleName() + ':' + getID(); + } + + Set getLanguageFiles(); + + InputStream getInputStreamCaseInsensitive(String path) throws IOException; + + Optional findFileCaseInsensitive(String path); + + static String toAbsolutePath(String path) { + LinkedList stack = new LinkedList<>(); + int skipCount = 0; + String[] split = path.split("[/\\\\]"); + + for (int i = split.length - 1; i >= 0; i--) { + String p = split[i]; + if (".".equals(p)) + continue; + else if ("..".equals(p)) { + skipCount++; + continue; + } + + if (skipCount > 0) { + skipCount--; + continue; + } + + stack.addFirst(p); + } + + if (skipCount > 0) + throw new IllegalArgumentException('\'' + path + "' leads outside root"); + + return String.join("/", stack); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/BlockConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/BlockConverter.java new file mode 100644 index 000000000..c8f9df8ff --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/BlockConverter.java @@ -0,0 +1,166 @@ +/* + * 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_2.wrapper.block; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.init.Blocks; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +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.Mod; +import nova.core.nativewrapper.NativeConverter; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.ForgeLoadable; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.CategoryConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.backward.BWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.backward.BWBlockFactory; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.FWItemBlock; +import nova.internal.core.Game; +import nova.internal.core.launch.NovaLauncher; + +import java.util.Arrays; +import java.util.Optional; + +/** + * @author Calclavia + */ +//TODO: Should be +public class BlockConverter implements NativeConverter, ForgeLoadable { + /** + * A map of all blockFactory to MC blocks registered + */ + public final BiMap blockFactoryMap = HashBiMap.create(); + + public static BlockConverter instance() { + return Game.natives().getNative(BlockFactory.class, net.minecraft.block.Block.class); + } + + @Override + public Class getNovaSide() { + return BlockFactory.class; + } + + @Override + public Class getNativeSide() { + return net.minecraft.block.Block.class; + } + + @Override + public BlockFactory toNova(net.minecraft.block.Block nativeBlock) { + //Prevent recursive wrapping + if (nativeBlock instanceof FWBlock) { + return ((FWBlock) nativeBlock).getFactory(); + } + + if (nativeBlock == Blocks.AIR) { + return Game.blocks().getAirBlock(); + } + + return blockFactoryMap.inverse().get(nativeBlock); + } + + public net.minecraft.block.Block toNative(Block novaBlock) { + //Prevent recursive wrapping + if (novaBlock instanceof BWBlock) { + return ((BWBlock) novaBlock).block(); + } + + return toNative(novaBlock.getFactory()); + } + + @Override + public net.minecraft.block.Block toNative(BlockFactory blockFactory) { + return blockFactoryMap.get(blockFactory); + } + + /** + * Register all Nova blocks + * + * @param evt The Minecraft Forge pre-initialization event + */ + @Override + public void preInit(FMLPreInitializationEvent evt) { + 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(block -> blockManager.register(new BWBlockFactory(block))); + } + + 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(); + if (!blockId.contains(":")) + blockId = NovaLauncher.instance().flatMap(NovaLauncher::getCurrentMod).map(Mod::id).orElse("nova") + ':' + blockId; + 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; + blockWrapper.setCreativeTab(CategoryConverter.instance().toNative(category, blockWrapper)); + } + } + + Game.logger().info("Registered block: {}", blockFactory.getID()); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlock.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlock.java new file mode 100644 index 000000000..359665469 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlock.java @@ -0,0 +1,273 @@ +/* + * 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_2.wrapper.block.backward; + +import net.minecraft.block.BlockSnow; +import net.minecraft.block.SoundType; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +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.Component; +import nova.core.component.fluid.FluidConsumer; +import nova.core.component.fluid.FluidHandler; +import nova.core.component.fluid.FluidProvider; +import nova.core.component.misc.Collider; +import nova.core.component.renderer.StaticRenderer; +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.Direction; +import nova.core.util.shape.Cuboid; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11_2.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.cuboid.CuboidConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.EntityConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.render.backward.BWBakedModel; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class BWBlock extends Block implements Storable { + private final IBlockState blockState; + @Store + private TileEntity mcTileEntity; + + public BWBlock(net.minecraft.block.Block block) { + this.blockState = block.getDefaultState(); + } + + @SuppressWarnings("deprecation") + public BWBlock(IBlockState blockState, World world, Vector3D pos) { + this.blockState = blockState; + components.add(new BWBlockTransform(this, world, pos)); + components.add(new BlockProperty.Opacity()).setOpacity(() -> blockState().getMaterial().isOpaque() ? 1 : 0); + BlockProperty.Replaceable replaceable = components.add(new BlockProperty.Replaceable()); + if (block() != Blocks.AIR) { + replaceable.setReplaceable(() -> block().canPlaceBlockAt((net.minecraft.world.World) blockAccess(), blockPos())); + } + + BlockProperty.BlockSound blockSound = components.add(new BlockProperty.BlockSound()); + SoundType soundType; + if (blockAccess() instanceof net.minecraft.world.World) + soundType = block().getSoundType(blockState(), (net.minecraft.world.World) blockAccess(), blockPos(), null); + else + soundType = block().getSoundType(); + + if (soundType.getPlaceSound() != null) + blockSound.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.PLACE, + new Sound(soundType.getPlaceSound().getSoundName().getResourceDomain(), + soundType.getPlaceSound().getSoundName().getResourcePath())); + + if (soundType.getBreakSound() != null) + blockSound.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.BREAK, + new Sound(soundType.getBreakSound().getSoundName().getResourceDomain(), + soundType.getBreakSound().getSoundName().getResourcePath())); + + if (soundType.getStepSound() != null) + blockSound.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.WALK, + new Sound(soundType.getStepSound().getSoundName().getResourceDomain(), + soundType.getStepSound().getSoundName().getResourcePath())); + + components.add(new LightEmitter()).setEmittedLevel(() -> blockState().getLightValue(blockAccess(), blockPos()) / 15d); + components.add(new Collider(this)) + .setBoundingBox(() -> { + AxisAlignedBB aabb = blockState().getBoundingBox(blockAccess(), blockPos()); + return new Cuboid(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ); + }).setOcclusionBoxes(entity -> { + List aabbs = new ArrayList<>(); + if (blockAccess() instanceof net.minecraft.world.World) + blockState().addCollisionBoxToList( + (net.minecraft.world.World) blockAccess(), + blockPos(), + CuboidConverter.instance().toNative(entity + .flatMap(e -> e.components.getOp(Collider.class)) + .map(c -> c.boundingBox.get()) + .orElseGet(() -> Cuboid.ONE.add(pos))), + aabbs, + entity.map(EntityConverter.instance()::toNative).orElse(null), + true + ); + return aabbs.stream() + .map(CuboidConverter.instance()::toNova) + .map(cuboid -> cuboid.subtract(pos)) + .collect(Collectors.toSet()); + }).setSelectionBoxes(entity -> { + final AxisAlignedBB bb; + if (blockAccess() instanceof net.minecraft.world.World) { + bb = block().getSelectedBoundingBox(blockState(), ((net.minecraft.world.World) blockAccess()), blockPos()); + } else { + bb = blockState().getBoundingBox(blockAccess(), blockPos()).offset(blockPos()); + } + Cuboid cuboid = CuboidConverter.instance().toNova(bb); + return Collections.singleton(cuboid.subtract(position())); + }); + components.add(new StaticRenderer()) + .onRender(model -> { + switch (blockState().getRenderType()) { + case INVISIBLE: + // rendering of invisible type + break; + case LIQUID: + // fluid rendering + // TODO + break; + case ENTITYBLOCK_ANIMATED: + // dynamic block rendering + // Handled by DynamicRenderer + break; + case MODEL: + // model rendering + model.addChild(new BWBakedModel(Minecraft.getMinecraft().getBlockRendererDispatcher() + .getModelForState(blockState()), DefaultVertexFormats.BLOCK, + Optional.of(blockState()), MathHelper.getPositionRandom(blockPos()))); + break; + default: + break; + } + }); + // TODO: TileEntity rendering using DynamicRenderer + + WrapperEvent.BWBlockCreate event = new WrapperEvent.BWBlockCreate(world, pos, this, block()); + Game.events().publish(event); + } + + @SuppressWarnings("unchecked") + private Set getSidedComponent(Class component, Set instances, Direction direction) { + if (!tile().isPresent()) { + return Collections.emptySet(); + } + + if (FluidProvider.class.isAssignableFrom(component) || + FluidConsumer.class.isAssignableFrom(component) || + FluidHandler.class.isAssignableFrom(component)) { +// return (Set) tile() +// .map(t -> t.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, DirectionConverter.instance().toNative(direction))) +// .map(BWFluidHandler::new) +// .map(Collections::singleton) +// .orElse(Collections.emptySet()); + } else { // TODO: Add Support for inventories + WrapperEvent.CapabilityToComponent event = new WrapperEvent.CapabilityToComponent<>(tile().get(), component, instances, direction); + Game.events().publish(event); + if (!event.instances.isEmpty()) + return event.instances; + } + + return Collections.emptySet(); + } + + @Override + public ItemFactory getItemFactory() { + return ItemConverter.instance().toNova(Item.getItemFromBlock(block())); + } + + public net.minecraft.block.Block block() { + return blockState.getBlock(); + } + + public int meta() { + return block().getMetaFromState(blockState()); + } + + public BlockPos blockPos() { + return VectorConverter.instance().toNative(position()); + } + + public IBlockAccess blockAccess() { + return WorldConverter.instance().toNative(world()); + } + + public IBlockState blockState() { + if (!components.has(BlockTransform.class)) + return blockState; + + IBlockState actualState = blockState.getActualState(blockAccess(), blockPos()); + return actualState.getBlock().getExtendedState(actualState, blockAccess(), blockPos()); + } + + public Optional tile() { + if (mcTileEntity == null && block().hasTileEntity(blockState())) { + mcTileEntity = blockAccess().getTileEntity(blockPos()); + } + return Optional.ofNullable(mcTileEntity); + } + + @Override + public boolean shouldDisplacePlacement() { + if (block() == Blocks.SNOW_LAYER && (blockState().getValue(BlockSnow.LAYERS) < 1)) { + return false; + } + + if (block() == Blocks.VINE || block() == Blocks.TALLGRASS || block() == Blocks.DEADBUSH || block().isReplaceable(blockAccess(), blockPos())) { + return false; + } + return super.shouldDisplacePlacement(); + } + + @Override + public void save(Data data) { + Storable.super.save(data); + tile().ifPresent(tile -> data.putAll(DataConverter.instance().toNova(tile.serializeNBT()))); + } + + @Override + public void load(Data data) { + Storable.super.load(data); + tile().ifPresent(tile -> tile.deserializeNBT(DataConverter.instance().toNative(data))); + } + + @Override + public String getLocalizedName() { + return block().getLocalizedName(); + } + + @Override + public String getUnlocalizedName() { + return block().getUnlocalizedName(); + } + + @Override + public String toString() { + return getID() + '(' + world() + '@' + x() + ',' + y() + ',' + z() + ')'; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlockFactory.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlockFactory.java new file mode 100644 index 000000000..8e298b2e6 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlockFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017 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_2.wrapper.block.backward; + +import net.minecraft.block.Block; +import nova.core.block.BlockFactory; + +/** + * @author ExE Boss + */ +public class BWBlockFactory extends BlockFactory { + + private final Block block; + + public BWBlockFactory(Block block) { + super(Block.REGISTRY.getNameForObject(block).toString(), () -> new BWBlock(block), factory -> {}); + this.block = block; + } + + public Block getBlock() { + return block; + } + + @Override + public String getLocalizedName() { + return getBlock().getLocalizedName(); + } + + @Override + public String getUnlocalizedName() { + return getBlock().getUnlocalizedName(); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlockTransform.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlockTransform.java new file mode 100644 index 000000000..d04e7404b --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/backward/BWBlockTransform.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017 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_2.wrapper.block.backward; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import nova.core.component.transform.BlockTransform; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Optional; + +/** + * @author ExE Boss + */ +public class BWBlockTransform extends BlockTransform { + + private final BWBlock block; + private World world; + private Vector3D position; + + public BWBlockTransform(BWBlock 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; + } + + public BlockPos blockPos() { + return VectorConverter.instance().toNative(position); + } + + public IBlockAccess blockAccess() { + return WorldConverter.instance().toNative(world); + } + + @Override + public void setWorld(World world) { + BlockPos pos = blockPos(); + net.minecraft.world.World oldWorld = (net.minecraft.world.World) WorldConverter.instance().toNative(this.world); + net.minecraft.world.World newWorld = (net.minecraft.world.World) WorldConverter.instance().toNative(world); + Optional tileEntity = Optional.ofNullable(oldWorld.getTileEntity(pos)); + Optional nbt = Optional.empty(); + if (tileEntity.isPresent()) { + NBTTagCompound compound = new NBTTagCompound(); + tileEntity.get().writeToNBT(compound); + nbt = Optional.of(compound); + } + newWorld.setBlockState(pos, block.blockState()); + oldWorld.removeTileEntity(pos); + oldWorld.setBlockToAir(pos); + Optional newTileEntity = Optional.ofNullable(newWorld.getTileEntity(pos)); + if (newTileEntity.isPresent() && nbt.isPresent()) { + newTileEntity.get().readFromNBT(nbt.get()); + } + this.world = world; + } + + @Override + public void setPosition(Vector3D position) { + BlockPos oldPos = blockPos(); + BlockPos newPos = VectorConverter.instance().toNative(position); + net.minecraft.world.World world = (net.minecraft.world.World) WorldConverter.instance().toNative(this.world); + Optional tileEntity = Optional.ofNullable(blockAccess().getTileEntity(oldPos)); + Optional nbt = Optional.empty(); + if (tileEntity.isPresent()) { + NBTTagCompound compound = new NBTTagCompound(); + tileEntity.get().writeToNBT(compound); + compound.setInteger("x", newPos.getX()); + compound.setInteger("y", newPos.getY()); + compound.setInteger("z", newPos.getZ()); + nbt = Optional.of(compound); + } + world.setBlockState(newPos, block.blockState()); + world.removeTileEntity(oldPos); + world.setBlockToAir(oldPos); + Optional newTileEntity = Optional.ofNullable(blockAccess().getTileEntity(newPos)); + if (newTileEntity.isPresent() && nbt.isPresent()) { + newTileEntity.get().readFromNBT(nbt.get()); + } + this.position = position; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/BlockPosition.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/BlockPosition.java new file mode 100644 index 000000000..f5b8234a9 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlock.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlock.java new file mode 100644 index 000000000..ed65dbf93 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlock.java @@ -0,0 +1,458 @@ +/* + * 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_2.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.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.math.MathUtil; +import nova.core.util.math.Vector3DUtil; +import nova.core.util.shape.Cuboid; +import nova.core.wrapper.mc.forge.v1_11_2.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.cuboid.CuboidConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.EntityConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +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; + //TODO: Hack. Bad practice. + public IBlockAccess lastExtendedWorld; + public BlockPos lastExtendedStatePos; + private Map harvestedBlocks = new HashMap<>(); + + private static Material getMcMaterial(Block dummy) { + if (dummy.components.has(BlockProperty.Opacity.class) || dummy.components.has(BlockProperty.Replaceable.class)) { + // TODO allow color selection + return new ProxyMaterial(MapColor.GRAY, + dummy.components.getOp(BlockProperty.Opacity.class), + dummy.components.getOp(BlockProperty.Replaceable.class)); + } else { + return Material.PISTON; + } + } + + public FWBlock(BlockFactory factory) { + this(factory, factory.build()); + } + + private FWBlock(BlockFactory factory, Block dummy) { + super(getMcMaterial(dummy)); + this.factory = factory; + this.dummy = dummy; + 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().getResourceDomain(), SoundType.STONE.getBreakSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.PLACE, new Sound(SoundType.STONE.getPlaceSound().getSoundName().getResourceDomain(), SoundType.STONE.getPlaceSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.WALK, new Sound(SoundType.STONE.getStepSound().getSoundName().getResourceDomain(), 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 = dummy.components + .getOp(BlockProperty.Opacity.class) + .map(o -> MathUtil.clamp((int) Math.round(o.getOpacity() * 255), 0, 255)) + .orElse(this.fullBlock ? 255 : 0); + this.translucent = !this.fullBlock; + } + + public BlockFactory getFactory() { + return this.factory; + } + + public Block getBlockInstance(IBlockAccess access, BlockPos position) { + return getBlockInstance(access, VectorConverter.instance().toNova(position)); + } + + 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(WorldConverter.instance().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 FWBlockTransform(block, world, position)); + if (!block.components.has(BlockProperty.BlockSound.class)) { + BlockProperty.BlockSound properties = block.components.add(new BlockProperty.BlockSound()); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.BREAK, new Sound(SoundType.STONE.getBreakSound().getSoundName().getResourceDomain(), SoundType.STONE.getBreakSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.PLACE, new Sound(SoundType.STONE.getPlaceSound().getSoundName().getResourceDomain(), SoundType.STONE.getPlaceSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.WALK, new Sound(SoundType.STONE.getStepSound().getSoundName().getResourceDomain(), SoundType.STONE.getStepSound().getSoundName().getResourcePath())); + } + 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, pos)); + } + } + + @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, pos); + } + + Block.DropEvent event = new Block.DropEvent(blockInstance); + blockInstance.events.publish(event); + + return event.drops + .stream() + .map(ItemConverter.instance()::toNative) + .collect(Collectors.toList()); + } + + @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) { + FWTile fwTile = FWTileLoader.loadTile(dummy.getID()); + fwTile.getBlock().components.getOrAdd(new TEBlockTransform(fwTile)); + if (!fwTile.getBlock().components.has(BlockProperty.BlockSound.class)) { + BlockProperty.BlockSound properties = fwTile.getBlock().components.add(new BlockProperty.BlockSound()); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.BREAK, new Sound(SoundType.STONE.getBreakSound().getSoundName().getResourceDomain(), SoundType.STONE.getBreakSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.PLACE, new Sound(SoundType.STONE.getPlaceSound().getSoundName().getResourceDomain(), SoundType.STONE.getPlaceSound().getSoundName().getResourcePath())); + properties.setBlockSound(BlockProperty.BlockSound.BlockSoundTrigger.WALK, new Sound(SoundType.STONE.getStepSound().getSoundName().getResourceDomain(), SoundType.STONE.getStepSound().getSoundName().getResourcePath())); + } + return fwTile; + } + + @Override + public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) { + lastExtendedWorld = world; + lastExtendedStatePos = pos; + return super.getExtendedState(state, world, pos); + } + + @Override + @Deprecated + public void neighborChanged(IBlockState state, World world, BlockPos pos, net.minecraft.block.Block other, BlockPos neighbor) { + onNeighborChange(world, pos, neighbor); + } + + @Override + public void onNeighborChange(IBlockAccess world, BlockPos pos, BlockPos neighbor) { + Block blockInstance = getBlockInstance(world, pos); + Block.NeighborChangeEvent evt = new Block.NeighborChangeEvent(Optional.of(VectorConverter.instance().toNova(neighbor))); + blockInstance.events.publish(evt); + } + + @Override + public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { + Block blockInstance = getBlockInstance(world, pos); + Block.RemoveEvent evt = new Block.RemoveEvent(Optional.of(EntityConverter.instance().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, pos); + Optional mop = Optional.ofNullable(player.rayTrace(10, 1)); + Block.LeftClickEvent evt = new Block.LeftClickEvent(EntityConverter.instance().toNova(player), + DirectionConverter.instance().toNova(mop.map(m -> m.sideHit).orElse(null)), + mop.map(m -> m.hitVec).map(VectorConverter.instance()::toNova).orElseGet(() -> VectorConverter.instance().toNova(pos))); + 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, pos); + Block.RightClickEvent evt = new Block.RightClickEvent(EntityConverter.instance().toNova(player), DirectionConverter.instance().toNova(side), 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, pos); + blockInstance.components.getOp(Collider.class).ifPresent(collider -> blockInstance.events.publish(new Collider.CollideEvent(EntityConverter.instance().toNova(entity)))); + } + + @Override + @Deprecated + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess access, BlockPos pos) { + Block blockInstance = getBlockInstance(access, pos); + 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, pos); + + if (blockInstance.components.has(Collider.class)) { + Collider collider = blockInstance.components.get(Collider.class); + Set cuboids = collider.selectionBoxes.apply(Optional.empty()); + Cuboid cuboid = cuboids.stream().reduce(collider.boundingBox.get(), + (c1, c2) -> new Cuboid(Vector3DUtil.min(c1.min, c2.min), Vector3DUtil.max(c1.max, c2.max))); + return CuboidConverter.instance().toNative(cuboid.add(VectorConverter.instance().toNova(pos))); + } + return super.getSelectedBoundingBox(state, world, pos); + } + + @Override + @Deprecated + public void addCollisionBoxToList(IBlockState state, World world, BlockPos pos, AxisAlignedBB boundingBox, List list, Entity entity, boolean b) { + Block blockInstance = getBlockInstance(world, pos); + blockInstance.components.getOp(Collider.class).ifPresent( + collider -> { + Set boxes = collider.occlusionBoxes.apply(Optional.ofNullable(entity != null ? EntityConverter.instance().toNova(entity) : null)); + + list.addAll( + boxes + .stream() + .map(c -> c.add(VectorConverter.instance().toNova(pos))) + .filter(c -> c.intersects(CuboidConverter.instance().toNova(boundingBox))) + .map(CuboidConverter.instance()::toNative) + .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 = getBlockInstance(world, pos).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, pos); + Optional opEmitter = blockInstance.components.getOp(LightEmitter.class); + + if (opEmitter.isPresent()) { + return (int) MathUtil.clamp(Math.round(opEmitter.get().emittedLevel.getAsDouble() * 15), 0, 15); + } 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, pos); + 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, pos); + 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, pos); + 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 factory.getUnlocalizedName(); + } + + @Override + public String getLocalizedName() { + return factory.getLocalizedName(); + } + + @Override + public float getExplosionResistance(World world, BlockPos pos, Entity exploder, Explosion explosion) { + // TODO: Maybe do something withPriority these parameters. + + // This number was calculated from the blast resistance of Stone, + // which requires exactly one cubic meter of TNT to get blown up. + // + // 1. During construction, the setResistance method is called + // on minecraft:stone with a value of 10. + // + // 2. The setResistance method multiplies that by 3 and assigns + // the result to the blockResistance instance variable. + // + // 3. Finally, the getExplosionResistance method divides the + // blockResistance instance variable by 5 and returns the result. + // + // From this we see that minecraft:stone’s final blast resistance is 6. + + return (float) getBlockInstance(world, pos).getResistance() * 6; + } + + @Override + @Deprecated + public float getBlockHardness(IBlockState state, World world, BlockPos pos) { + return (float) getBlockInstance(world, pos).getHardness() * 2; + } + + @Override + public int getLightOpacity(IBlockState state, IBlockAccess world, BlockPos pos) { + return getBlockInstance(world, pos) + .components.getOp(BlockProperty.Opacity.class) + .map(o -> MathUtil.clamp((int) Math.round(o.getOpacity() * 255), 0, 255)) + .orElse(this.fullBlock ? 255 : 0); + } + + @Override + public boolean isReplaceable(IBlockAccess world, BlockPos pos) { + return getBlockInstance(world, pos) + .components.getOp(BlockProperty.Replaceable.class) + .filter(BlockProperty.Replaceable::isReplaceable) + .isPresent(); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlockSound.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlockSound.java new file mode 100644 index 000000000..9774f6408 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlockSound.java @@ -0,0 +1,47 @@ +package nova.core.wrapper.mc.forge.v1_11_2.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; + +/** + * @author winsock, soniex2, ExE Boss + */ +public class FWBlockSound extends SoundType { + private final BlockProperty.BlockSound blockSound; + + /** + * Construct a new FWBlockSound + * @param blockSound The BlockSound to use. + */ + public FWBlockSound(BlockProperty.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() { + return blockSound.getSound(BlockProperty.BlockSound.BlockSoundTrigger.BREAK) + .map(sound -> (sound.domain.isEmpty() && !sound.name.contains(".")) ? "dig." + sound.name : sound.getID()) + .map(soundID -> SoundEvent.REGISTRY.getObject(new ResourceLocation(soundID))) + .orElseGet(super::getBreakSound); + } + + @Override + public SoundEvent getStepSound() { + return blockSound.getSound(BlockProperty.BlockSound.BlockSoundTrigger.WALK) + .map(sound -> (sound.domain.isEmpty() && !sound.name.contains(".")) ? "step." + sound.name : sound.getID()) + .map(soundID -> SoundEvent.REGISTRY.getObject(new ResourceLocation(soundID))) + .orElseGet(super::getBreakSound); + } + + @Override + public SoundEvent getPlaceSound() { + return blockSound.getSound(BlockProperty.BlockSound.BlockSoundTrigger.PLACE) + .map(sound -> sound.domain.isEmpty() ? "step." + sound.name : sound.getID()) + .map(soundID -> SoundEvent.REGISTRY.getObject(new ResourceLocation(soundID))) + .orElseGet(super::getPlaceSound); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlockTransform.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlockTransform.java new file mode 100644 index 000000000..d8fdf3eb1 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWBlockTransform.java @@ -0,0 +1,106 @@ +/* + * 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_2.wrapper.block.forward; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import nova.core.block.Block; +import nova.core.component.transform.BlockTransform; +import nova.core.retention.Data; +import nova.core.retention.Storable; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Optional; + +/** + * @author Calclavia + */ +public class FWBlockTransform extends BlockTransform { + + private Block block; + private World world; + private Vector3D position; + + public FWBlockTransform(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; + } + + public BlockPos blockPos() { + return VectorConverter.instance().toNative(position); + } + + public IBlockAccess blockAccess() { + return WorldConverter.instance().toNative(world); + } + + @Override + public void setWorld(World world) { + world.setBlock(position, block.getFactory()); + Optional data = Optional.empty(); + if (block instanceof Storable) { + data = Optional.of(new Data()); + ((Storable) block).save(data.get()); + } + this.world.removeBlock(position); + Optional newBlock = world.getBlock(position); + if (newBlock.isPresent()) { + block = newBlock.get(); + if (newBlock.get() instanceof Storable && data.isPresent()) { + ((Storable) newBlock.get()).load(data.get()); + } + } + this.world = world; + } + + @Override + public void setPosition(Vector3D position) { + world.setBlock(position, block.getFactory()); + Optional data = Optional.empty(); + if (block instanceof Storable) { + data = Optional.of(new Data()); + ((Storable) block).save(data.get()); + } + world.removeBlock(this.position); + Optional newBlock = world.getBlock(position); + if (newBlock.isPresent()) { + block = newBlock.get(); + if (newBlock.get() instanceof Storable && data.isPresent()) { + ((Storable) newBlock.get()).load(data.get()); + } + } + this.position = position; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTile.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTile.java new file mode 100644 index 000000000..0a18833ac --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTile.java @@ -0,0 +1,210 @@ +/* + * 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_2.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 net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +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.Direction; +import nova.core.wrapper.mc.forge.v1_11_2.network.netty.MCNetworkManager; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.NovaCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter; +import nova.internal.core.Game; + +import java.io.IOException; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * A Minecraft TileEntity to Nova block wrapper + * @author Calclavia + */ +public class FWTile extends TileEntity implements NovaCapabilityProvider { + + protected String blockID; + protected Block block; + protected Data cacheData = null; + + public FWTile() {} + + public FWTile(String blockID) { + this.blockID = blockID; + } + + public Block getBlock() { + return block; + } + + public void setBlock(Block block) { + if (block.components.has(TEBlockTransform.class)) + block.components.remove(TEBlockTransform.class); + block.components.getOrAdd(new TEBlockTransform(this)); + 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(); + if (block.components.has(TEBlockTransform.class)) + block.components.remove(TEBlockTransform.class); + block.components.getOrAdd(new TEBlockTransform(this)); + + 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", DataConverter.instance().toNative(data)); + } + } + + return nbt; + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + + blockID = nbt.getString("novaID"); + cacheData = DataConverter.instance().toNova(nbt.getCompoundTag("nova")); + } + + @Override + public boolean hasCapability(Capability capability, Direction direction) { + if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { +// return +// block.components.has(FluidProvider.class, direction) || +// block.components.has(FluidConsumer.class, direction) || +// block.components.has(FluidHandler.class, direction) || +// block instanceof SidedTankProvider; + } else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return false; // TODO: implement + } + + return false; + } + + @Override + public boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return hasCapability(capability, DirectionConverter.instance().toNova(facing)) || super.hasCapability(capability, facing); + } + + @Override + @SuppressWarnings("unchecked") + public Optional getCapability(Capability capability, Direction direction) { + if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { +// return (Optional) Optional.of(new FWFluidHandler( +// block.components.getOp(FluidProvider.class, direction), +// block.components.getOp(FluidConsumer.class, direction), +// block.components.getOp(FluidHandler.class, direction), +// Optional.of(block) +// .filter(b -> b instanceof SidedTankProvider) +// .map(b -> (SidedTankProvider) b), direction)).filter(FWFluidHandler::isPresent); + } else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return Optional.empty(); // TODO: implement + } + + return Optional.empty(); + } + + @Override + @Nullable + public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return getCapability(capability, DirectionConverter.instance().toNova(facing)) + .orElseGet(() -> super.getCapability(capability, facing)); + } + + private static class FWPacketUpdateTileEntity extends SPacketUpdateTileEntity { + private final Packet packet; + + private FWPacketUpdateTileEntity(Packet packet, BlockPos blockPosIn, int metadataIn, NBTTagCompound compoundIn) { + super(blockPosIn, metadataIn, compoundIn); + this.packet = packet; + } + + @Override + @SuppressWarnings("unchecked") + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileLoader.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileLoader.java new file mode 100644 index 000000000..f9470e90f --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileLoader.java @@ -0,0 +1,81 @@ +/* + * 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_2.wrapper.block.forward; + +import net.minecraft.nbt.NBTTagCompound; +import nova.core.block.Block; +import nova.core.block.BlockFactory; +import nova.core.component.Updater; +import nova.core.wrapper.mc.forge.v1_11_2.asm.lib.ComponentInjector; +import nova.core.wrapper.mc.forge.v1_11_2.util.WrapperEvent; +import nova.internal.core.Game; + +import java.util.Optional; + +/** + * @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); + ComponentInjector inject = (block instanceof Updater) ? updaterInjector : injector; + FWTile tile = inject.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); + ComponentInjector inject = (block instanceof Updater) ? updaterInjector : injector; + FWTile tile = inject.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileRenderer.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileRenderer.java new file mode 100644 index 000000000..3bf3b151f --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileRenderer.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_2.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 nova.core.block.Block; +import nova.core.component.renderer.DynamicRenderer; +import nova.core.wrapper.mc.forge.v1_11_2.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11_2.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 partialTicks, int destroyStage) { + 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(te.getWorld()); + Tessellator.getInstance().draw(); + RenderUtility.disableBlending(); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileUpdater.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileUpdater.java new file mode 100644 index 000000000..112d778cd --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/FWTileUpdater.java @@ -0,0 +1,46 @@ +/* + * 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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/ProxyMaterial.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/ProxyMaterial.java new file mode 100644 index 000000000..db920ac5b --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/ProxyMaterial.java @@ -0,0 +1,42 @@ +package nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward; + +import net.minecraft.block.material.MapColor; +import net.minecraft.block.material.Material; +import nova.core.block.component.BlockProperty; + +import java.util.Optional; + +/** + * @author soniex2 + */ +public class ProxyMaterial extends Material { + private final Optional opacity; + private final Optional replaceable; + + /** + * Construct a new proxy material. + * @param color The map color. + * @param opacity The Opacity to use. + * @param replaceable If this block is replaceable. + */ + public ProxyMaterial(MapColor color, Optional opacity, Optional replaceable) { + super(color); + this.opacity = opacity; + this.replaceable = replaceable; + } + + @Override + public boolean blocksLight() { + return opacity.map(BlockProperty.Opacity::isOpaque).orElseGet(super::blocksLight); + } + + @Override + public boolean isOpaque() { + return opacity.map(BlockProperty.Opacity::isOpaque).orElseGet(super::isOpaque); + } + + @Override + public boolean isReplaceable() { + return replaceable.map(BlockProperty.Replaceable::isReplaceable).orElseGet(super::isReplaceable); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/TEBlockTransform.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/TEBlockTransform.java new file mode 100644 index 000000000..1c8852c1e --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/forward/TEBlockTransform.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017 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_2.wrapper.block.forward; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import nova.core.block.Block; +import nova.core.component.transform.BlockTransform; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Objects; + +/** + * @author ExE Boss + */ +public class TEBlockTransform extends BlockTransform { + + private final FWTile tileEntity; + + public TEBlockTransform(FWTile tileEntity) { + this.tileEntity = tileEntity; + } + + public Block block() { + return tileEntity.block; + } + + @Override + public Vector3D position() { + return VectorConverter.instance().toNova(tileEntity.getPos()); + } + + @Override + public World world() { + return WorldConverter.instance().toNova(tileEntity.getWorld()); + } + + public BlockPos blockPos() { + return tileEntity.getPos(); + } + + public IBlockAccess blockAccess() { + return tileEntity.getWorld(); + } + + @Override + public void setWorld(World world) { + world().setBlock(position(), tileEntity.block.getFactory()); + world().removeBlock(position()); + Objects.requireNonNull((FWTile) WorldConverter.instance().toNative(world).getTileEntity(blockPos())).setBlock(tileEntity.block); + } + + @Override + public void setPosition(Vector3D position) { + world().setBlock(position, tileEntity.block.getFactory()); + world().removeBlock(position()); + Objects.requireNonNull((FWTile) blockAccess().getTileEntity(VectorConverter.instance().toNative(position))).setBlock(tileEntity.block); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/world/BWWorld.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/world/BWWorld.java new file mode 100644 index 000000000..88ba22ae9 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/world/BWWorld.java @@ -0,0 +1,188 @@ +/* + * 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_2.wrapper.block.world; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.init.Blocks; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import nova.core.block.Block; +import nova.core.block.BlockFactory; +import nova.core.component.misc.FactoryProvider; +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_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.BlockConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.backward.BWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlockTransform; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.cuboid.CuboidConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.EntityConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.MCEntityTransform; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 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! + // TODO: Return an optional + 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) { + IBlockState blockState = access.getBlockState(new BlockPos((int) position.getX(), (int) position.getY(), (int) position.getZ())); + net.minecraft.block.Block block = blockState == null ? null : blockState.getBlock(); + if (blockState == null || block == null || block == Blocks.AIR) { + Block airBlock = Game.blocks().getAirBlock().build(); + airBlock.components.add(new FWBlockTransform(airBlock, this, position)); + return Optional.of(airBlock); + } + if (block instanceof FWBlock) { + return Optional.of(((FWBlock) block).getBlockInstance(access, position)); + } else { + BWBlock wrappedBlock = new BWBlock(blockState, this, position); + Game.blocks().get(Objects.toString(net.minecraft.block.Block.REGISTRY.getNameForObject(block))) + .ifPresent(blockFactory -> wrappedBlock.components.getOrAdd(new FactoryProvider(blockFactory))); + return Optional.of(wrappedBlock); + } + } + + @Override + public boolean setBlock(Vector3D position, BlockFactory blockFactory) { + net.minecraft.block.Block mcBlock = BlockConverter.instance().toNative(blockFactory); + BlockPos pos = VectorConverter.instance().toNative(position); + 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 + @SuppressWarnings("unchecked") + public T addClientEntity(T entity) { + return (T) NovaMinecraft.proxy.spawnParticle(world(), entity); + } + + @Override + public void removeEntity(Entity entity) { + if (access instanceof net.minecraft.world.World) { + net.minecraft.entity.Entity wrapper = entity.components.get(MCEntityTransform.class).wrapper; + wrapper.setDead(); + world().removeEntity(wrapper); + } + } + + @Override + public Set getEntities(Cuboid bound) { + return Optional.of(access) + .filter(access -> access instanceof net.minecraft.world.World) + .map(access -> world().getEntitiesWithinAABB(net.minecraft.entity.Entity.class, CuboidConverter.instance().toNative(bound))) + .orElseGet(Collections::emptyList) + .stream() + .map(EntityConverter.instance()::toNova) + .collect(Collectors.toSet()); + } + + @Override + public Entity addEntity(Vector3D position, Item item) { + EntityItem entityItem = new EntityItem(world(), position.getX(), position.getY(), position.getZ(), ItemConverter.instance().toNative(item)); + world().spawnEntity(entityItem); + return EntityConverter.instance().toNova(entityItem); + } + + @Override + public Optional getEntity(String uniqueID) { + return Optional.ofNullable(EntityConverter.instance().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.domain.isEmpty() ? sound.name : sound.getID())), + SoundCategory.BLOCKS, sound.volume, sound.pitch, true); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/world/WorldConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/world/WorldConverter.java new file mode 100644 index 000000000..39c846414 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/block/world/WorldConverter.java @@ -0,0 +1,69 @@ +/* + * 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_2.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 { + + public static WorldConverter instance() { + return Game.natives().getNative(World.class, IBlockAccess.class); + } + + @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).access; + } + + throw new UnsupportedOperationException("Attempt to convert a world that is not a BWWorld!"); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/CapabilityUtil.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/CapabilityUtil.java new file mode 100644 index 000000000..3b5c5f7cc --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/CapabilityUtil.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2017 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_2.wrapper.capability; + +import net.minecraft.nbt.NBTBase; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.Capability.IStorage; +import nova.core.util.Direction; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; + +import java.util.function.Supplier; + +/** + * @author ExE Boss + */ +public class CapabilityUtil { + + private CapabilityUtil() {} + + /** + * Helper method to easily generate an {@link IStorage} using lambda expressions. + * + * @param The Capability type + * @param The NBT Tag Compound type + * @param writer The Writer + * @param reader The Reader + * @return A new {@link IStorage} instance + */ + public static IStorage createStorage(StorageWriter writer, StorageReader reader) { + return new Capability.IStorage() { + @Override + public NBT writeNBT(Capability capability, T instance, EnumFacing side) { + return writer.writeNBT(capability, instance, DirectionConverter.instance().toNova(side)); + } + + @Override + @SuppressWarnings("unchecked") + public void readNBT(Capability capability, T instance, EnumFacing side, NBTBase nbt) { + reader.readNBT(capability, instance, DirectionConverter.instance().toNova(side), (NBT) nbt); + } + }; + } + + public static IStorage unsupportedStorage() { + return unsupportedStorage((String) null); + } + + public static IStorage unsupportedStorage(String reason) { + return unsupportedStorage(() -> reason); + } + + public static IStorage unsupportedStorage(Supplier reason) { + return createStorage((capability, instance, side) -> {throw new UnsupportedOperationException(reason.get());}, + (capability, instance, side, nbt) -> {throw new UnsupportedOperationException(reason.get());}); + } + + @FunctionalInterface + public static interface StorageWriter { + NBT writeNBT(Capability capability, T instance, Direction side); + } + + @FunctionalInterface + public static interface StorageReader { + void readNBT(Capability capability, T instance, Direction side, NBT nbt); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/FWCapabilityProvider.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/FWCapabilityProvider.java new file mode 100644 index 000000000..0758a19f3 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/FWCapabilityProvider.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_2.wrapper.capability.forward; + +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; +import nova.core.component.ComponentProvider; +import nova.core.component.SidedComponentMap; +import nova.core.util.Direction; + +import java.util.Optional; + +/** + * + * @author ExE Boss + */ +public class FWCapabilityProvider implements NovaCapabilityProvider { + + private final ComponentProvider componentProvider; + + public FWCapabilityProvider(ComponentProvider componentProvider) { + this.componentProvider = componentProvider; + } + + @Override + public boolean hasCapability(Capability capability, Direction direction) { + if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { +// return +// getComponent(FluidProvider.class, direction).isPresent() || +// getComponent(FluidConsumer.class, direction).isPresent() || +// getComponent(FluidHandler.class, direction).isPresent() || +// componentProvider instanceof SidedTankProvider; + } else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return false; // TODO: implement + } + + return false; + } + + @Override + @SuppressWarnings("unchecked") + public Optional getCapability(Capability capability, Direction direction) { + if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { +// return (Optional) Optional.of(new FWFluidHandler( +// getComponent(FluidProvider.class, direction), +// getComponent(FluidConsumer.class, direction), +// getComponent(FluidHandler.class, direction), +// Optional.of(componentProvider) +// .filter(p -> p instanceof SidedTankProvider) +// .map(p -> (SidedTankProvider) p), direction)).filter(FWFluidHandler::isPresent); + } else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return Optional.empty(); // TODO: implement + } + + return Optional.empty(); + } + + private Optional getComponent(Class component, Direction direction) { + if (componentProvider.components instanceof SidedComponentMap) { + return ((SidedComponentMap) componentProvider.components).getOp(component, direction); + } else { + return componentProvider.components.getOp(component); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/NovaCapabilityProvider.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/NovaCapabilityProvider.java new file mode 100644 index 000000000..01b42ecec --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/NovaCapabilityProvider.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017 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_2.wrapper.capability.forward; + +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import nova.core.util.Direction; +import nova.core.util.EnumSelector; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; + +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * @author ExE Boss + */ +public interface NovaCapabilityProvider extends ICapabilityProvider { + + /** + * Determines if this object has support for the capability in question on the specific side. + * The return value of this might change during runtime if this object gains or looses support + * for a capability. + *

+ * Example: + * A Pipe getting a cover placed on one side causing it lose the + * {@link nova.core.component.inventory.Inventory} attachment function for that side. + * + * @param capability The capability to check. + * @param direction The Side to check from: @link nova.core.util.Direction.UNKNOWN UNKNOWN} + * is defined to represent 'internal' or 'self' or used for cases where side doesn't matter. + * @return True if this object supports the capability for this side. + */ + boolean hasCapability(@Nonnull Capability capability, @Nonnull Direction direction); + + @Override + default boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return hasCapability(capability, DirectionConverter.instance().toNova(facing)); + } + + /** + * Retrieves the handler for the capability requested on the specific side. + * The return value is {@link Optional#empty()} when the object does not support the capability for the direction. + * The return value can be the same for multiple faces. + *

+ * @param capability The capability to check. + * @param direction The Side to check from: @link nova.core.util.Direction.UNKNOWN UNKNOWN} + * is defined to represent 'internal' or 'self' or used for cases where side doesn't matter. + * @param The capability type to check. + * @return The requested capability. Returns an empty optional when + * {@link #hasCapability(Capability, EnumFacing)} would return false. + */ + @Nonnull + Optional getCapability(@Nonnull Capability capability, @Nonnull Direction direction); + + @Override + @Nullable + default T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return getCapability(capability, DirectionConverter.instance().toNova(facing)).orElse(null); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/cuboid/CuboidConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/cuboid/CuboidConverter.java new file mode 100644 index 000000000..864a99fc7 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/cuboid/CuboidConverter.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_2.wrapper.cuboid; + +import net.minecraft.util.math.AxisAlignedBB; +import nova.core.nativewrapper.NativeConverter; +import nova.core.util.shape.Cuboid; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +/** + * @author Calclavia + */ +public class CuboidConverter implements NativeConverter { + + public static CuboidConverter instance() { + return Game.natives().getNative(Cuboid.class, AxisAlignedBB.class); + } + + @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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/DataConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/DataConverter.java new file mode 100644 index 000000000..6a66fc7f2 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/DataConverter.java @@ -0,0 +1,174 @@ +/* + * 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_2.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.Optional; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Utility that manages common NBT queueSave and load methods + * @author Calclavia + */ +public class DataConverter implements NativeConverter { + + public static DataConverter instance() { + return Game.natives().getNative(Data.class, NBTTagCompound.class); + } + + @Override + public Class getNovaSide() { + return Data.class; + } + + @Override + public Class getNativeSide() { + return NBTTagCompound.class; + } + + @Override + @Nonnull + public Data toNova(@Nullable NBTTagCompound nbt) { + Data data = new Data(); + if (nbt != null) { + data.className = nbt.getString("class"); + Set keys = nbt.getKeySet(); + keys.stream() + .filter(k -> k != null && !"class".equals(k)) + .filter(Data.ILLEGAL_SUFFIX.asPredicate().negate()) + .forEach(k -> Optional.ofNullable(load(nbt, k)).ifPresent(v -> data.put(k, v))); + } + return data; + } + + @Override + @Nullable + public NBTTagCompound toNative(@Nullable Data data) { + if (data == null) { + return null; + } + + return toNative(new NBTTagCompound(), data); + } + + @Nonnull + public NBTTagCompound toNative(@Nonnull NBTTagCompound nbt, @Nonnull 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 + */ + @Nonnull + public NBTTagCompound save(@Nonnull NBTTagCompound tag, @Nonnull String key, @Nullable 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 + */ + @Nullable + public Object load(@Nullable NBTTagCompound tag, @Nullable 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/NBTStorable.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/NBTStorable.java new file mode 100644 index 000000000..5df63de31 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/NBTStorable.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017 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_2.wrapper.data; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.INBTSerializable; +import nova.core.retention.Data; +import nova.core.retention.Storable; + +/** + * @author ExE Boss + */ +public interface NBTStorable extends Storable, INBTSerializable { + + @Override + default NBTTagCompound serializeNBT() { + Data data = new Data(); + save(data); + return DataConverter.instance().toNative(data); + } + + @Override + default void deserializeNBT(NBTTagCompound nbt) { + load(DataConverter.instance().toNova(nbt)); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/EntityConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/EntityConverter.java new file mode 100644 index 000000000..a08eac203 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/EntityConverter.java @@ -0,0 +1,96 @@ +/* + * 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_2.wrapper.entity; + +import net.minecraft.util.EnumParticleTypes; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +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.nativewrapper.NativeConverter; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.ForgeLoadable; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.backward.BWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.FWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.MCEntityTransform; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.particle.backward.BWParticle; +import nova.internal.core.Game; + +import java.util.Optional; + +public class EntityConverter implements NativeConverter, ForgeLoadable { + + public static EntityConverter instance() { + return Game.natives().getNative(Entity.class, net.minecraft.entity.Entity.class); + } + + @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(FMLPreInitializationEvent evt) { + /** + * 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/backward/BWEntity.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/backward/BWEntity.java new file mode 100644 index 000000000..230601d04 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/backward/BWEntity.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_2.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_2.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.MCEntityTransform; +import nova.core.wrapper.mc.forge.v1_11_2.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; + + 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 getUniqueID() { + return entity.getGameProfile().getId().toString(); + } + + @Override + public InventoryPlayer getInventory() { + return inventory; + } + + @Override + public String getUsername() { + return entity.getGameProfile().getName(); + } + + @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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/BWRigidBody.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/BWRigidBody.java new file mode 100644 index 000000000..9a74e0df4 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntity.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntity.java new file mode 100644 index 000000000..fd8cebded --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntity.java @@ -0,0 +1,278 @@ +/* + * 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_2.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.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import net.minecraftforge.items.CapabilityItemHandler; +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.Direction; +import nova.core.util.shape.Cuboid; +import nova.core.wrapper.mc.forge.v1_11_2.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.NovaCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.cuboid.CuboidConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter; +import nova.internal.core.Game; + +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Entity wrapper + * @author Calclavia + */ +public class FWEntity extends net.minecraft.entity.Entity implements IEntityAdditionalSpawnData, NovaCapabilityProvider { + + 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(DataConverter.instance().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); + DataConverter.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 + Optional.ofNullable(getCollisionBoundingBox()) + .map(CuboidConverter.instance()::toNova) + .ifPresent(this::setBounds); + } + + /** + * 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 + Optional.ofNullable(transform) + .map(EntityTransform::position) + .map(bounds::add) + .map(CuboidConverter.instance()::toNative) + .ifPresent(this::setEntityBoundingBox); + } + + @Override + public void setDead() { + wrapped.events.publish(new Stateful.UnloadEvent()); + super.setDead(); + } + + @Override + public boolean hasCapability(Capability capability, Direction direction) { + if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { +// return +// wrapped.components.has(FluidProvider.class) || +// wrapped.components.has(FluidConsumer.class) || +// wrapped.components.has(FluidHandler.class) || +// wrapped instanceof SidedTankProvider; + } else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return false; // TODO: implement + } + + return false; + } + + @Override + public boolean hasCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return hasCapability(capability, DirectionConverter.instance().toNova(facing)) || super.hasCapability(capability, facing); + } + + @Override + @SuppressWarnings("unchecked") + public Optional getCapability(Capability capability, Direction direction) { + if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { +// return (Optional) Optional.of(new FWFluidHandler( +// wrapped.components.getOp(FluidProvider.class), +// wrapped.components.getOp(FluidConsumer.class), +// wrapped.components.getOp(FluidHandler.class), +// Optional.of(wrapped) +// .filter(e -> e instanceof SidedTankProvider) +// .map(e -> (SidedTankProvider) e), direction)).filter(FWFluidHandler::isPresent); + } else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { + return Optional.empty(); // TODO: implement + } + + return Optional.empty(); + } + + @Override + @Nullable + public T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) { + return getCapability(capability, DirectionConverter.instance().toNova(facing)) + .orElseGet(() -> super.getCapability(capability, facing)); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntityRenderer.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntityRenderer.java new file mode 100644 index 000000000..111fced59 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.particle.forward.FWParticle; +import nova.core.wrapper.mc.forge.v1_11_2.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.ITEM); + model.render(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.ITEM); + model.render(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, entity.wrapped, x, y, z); + } + + @Override + protected ResourceLocation getEntityTexture(FWEntity entity) { + return null; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/MCEntityTransform.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/MCEntityTransform.java new file mode 100644 index 000000000..23814613b --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/MCEntityTransform.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_2.wrapper.entity.forward; + +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraftforge.common.DimensionManager; +import nova.core.component.transform.EntityTransform; +import nova.core.util.UniqueIdentifiable; +import nova.core.util.math.RotationUtil; +import nova.core.util.math.Vector3DUtil; +import nova.core.world.World; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +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 implements UniqueIdentifiable { + 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 WorldConverter.instance().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]); + } + + @Override + public String getUniqueID() { + return wrapper.getUniqueID().toString(); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/BWInventory.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/BWInventory.java new file mode 100644 index 000000000..ee9e28e69 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/BWInventory.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_2.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.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +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 slot) { + return Optional.ofNullable(wrapped.getStackInSlot(slot)).map(ItemConverter.instance()::toNova); + } + + @Override + public boolean set(int slot, Item item) { + wrapped.setInventorySlotContents(slot, ItemConverter.instance().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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/FWInventory.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/FWInventory.java new file mode 100644 index 000000000..5dc81b61d --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/InventoryConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/InventoryConverter.java new file mode 100644 index 000000000..f53814f64 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/inventory/InventoryConverter.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_2.wrapper.inventory; + +import net.minecraft.inventory.IInventory; +import nova.core.component.inventory.Inventory; +import nova.core.nativewrapper.NativeConverter; +import nova.internal.core.Game; + +/** + * @author Calclavia + */ +public class InventoryConverter implements NativeConverter { + + public static InventoryConverter instance() { + return Game.natives().getNative(Inventory.class, IInventory.class); + } + + @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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/ItemConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/ItemConverter.java new file mode 100644 index 000000000..232a16948 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/ItemConverter.java @@ -0,0 +1,342 @@ +/* + * 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_2.wrapper.item; + +import com.google.common.collect.HashBiMap; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.CapabilityManager; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.registry.GameRegistry; +import nova.core.block.BlockFactory; +import nova.core.component.Category; +import nova.core.event.ItemEvent; +import nova.core.item.Item; +import nova.core.item.ItemBlock; +import nova.core.item.ItemFactory; +import nova.core.loader.Mod; +import nova.core.nativewrapper.NativeConverter; +import nova.core.retention.Data; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.ForgeLoadable; +import nova.core.wrapper.mc.forge.v1_11_2.launcher.NovaMinecraft; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.CategoryConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.BlockConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.CapabilityUtil; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.backward.BWItem; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.backward.BWItemFactory; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.FWItem; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.IFWItem; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.NovaItem; +import nova.internal.core.Game; +import nova.internal.core.launch.InitializationException; +import nova.internal.core.launch.NovaLauncher; + +import java.util.LinkedList; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * The main class responsible for wrapping items. + * @author Calclavia, Stan Hebben + */ +public class ItemConverter implements NativeConverter, ForgeLoadable { + + /** + * A map of all items registered + */ + private final HashBiMap map = HashBiMap.create(); + private final LinkedList nativeConversion = new LinkedList<>(); + + public static ItemConverter instance() { + return Game.natives().getNative(Item.class, ItemStack.class); + } + + @Override + public Class getNovaSide() { + return Item.class; + } + + @Override + public Class getNativeSide() { + return ItemStack.class; + } + + public ItemFactory toNova(net.minecraft.item.Item item) { + if (item instanceof IFWItem) { + return ((IFWItem) item).getItemFactory(); + } else { + return registerMinecraftMapping(item, 0); + } + } + + @Override + public Item toNova(@Nonnull ItemStack stack) { + return getNovaItem(stack).setCount(stack.getCount()); + } + + public Item getNovaItem(@Nonnull ItemStack stack) { + if (stack.getItemDamage() == net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE) { + // TODO: Deal withPriority wildcard meta values - important for the ore dictionary + ItemStack copy = stack.copy(); + copy.setItemDamage(0); + return getNovaItem(copy); // Preserve capabilities + } + + return Optional.ofNullable(stack.getCapability(NovaItem.CAPABILITY, null)) + .map(wrapped -> wrapped.item) + .orElseGet(() -> { + ItemFactory itemFactory = registerMinecraftMapping(stack.getItem(), stack.getItemDamage()); + Data data = stack.getTagCompound() != null ? DataConverter.instance().toNova(stack.getTagCompound()) : new Data(); + if (!stack.getHasSubtypes() && stack.getItemDamage() > 0) { + data.put("damage", stack.getItemDamage()); + } + return itemFactory.build(data); + }); + } + + @Override + public ItemStack toNative(@Nullable Item item) { + if (item == null) { + return ItemStack.EMPTY; + } + + //Prevent recusive wrapping + if (item instanceof BWItem) { + return ((BWItem) item).makeItemStack(item.count()); + } else { + MinecraftItemMapping mapping = get(item.getFactory()); + if (mapping == null) { + throw new InitializationException("Missing mapping for " + item.getID()); + } + nativeConversion.push(item); + return new ItemStack(mapping.item, item.count(), mapping.meta); + } + } + + public ItemStack toNative(@Nonnull ItemFactory itemFactory) { + Objects.requireNonNull(itemFactory); + MinecraftItemMapping mapping = get(itemFactory); + if (mapping == null) { + throw new InitializationException("Missing mapping for " + itemFactory.getID()); + } + if (!(itemFactory instanceof BWItemFactory)) + nativeConversion.push(itemFactory.build()); + return new ItemStack(mapping.item, 1, mapping.meta); + } + + public ItemStack toNative(String id) { + return Game.items().get(id).map(this::toNative).get(); + } + + public Optional popNativeConversion() { + return Optional.ofNullable(nativeConversion.poll()); + } + + 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(DataConverter.instance().toNative(item.getFactory().save(item))); + return itemStack; + } + + /** + * Register all Nova blocks + */ + @Override + public void preInit(FMLPreInitializationEvent evt) { + registerCapabilities(); + registerNOVAItemsToMinecraft(); + registerMinecraftItemsToNOVA(); + registerSubtypeResolution(); + } + + private void registerCapabilities() { + CapabilityManager.INSTANCE.register(NovaItem.class, CapabilityUtil.createStorage( + (capability, instance, side) -> instance.serializeNBT(), + (capability, instance, side, nbt) -> instance.deserializeNBT(nbt)), () -> null); + } + + 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()); + } + } 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(); + if (!itemId.contains(":")) + itemId = NovaLauncher.instance().flatMap(NovaLauncher::getCurrentMod).map(Mod::id).orElse("nova") + ':' + itemId; + 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); + itemWrapper.setCreativeTab(CategoryConverter.instance().toNative(category, itemWrapper)); + } + + Game.logger().info("Registered item: {}", itemFactory.getID()); + } + } + + 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.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 { + @Nonnull public final net.minecraft.item.Item item; + @Nonnull public final int meta; + + public MinecraftItemMapping(@Nonnull net.minecraft.item.Item item, int meta) { + this.item = item; + this.meta = item.getHasSubtypes() ? meta : 0; + } + + public MinecraftItemMapping(@Nonnull ItemStack itemStack) { + this.item = itemStack.getItem(); + this.meta = itemStack.getHasSubtypes() ? itemStack.getItemDamage() : 0; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null || getClass() != other.getClass()) return false; + return (meta == ((MinecraftItemMapping) other).meta + && item.equals(((MinecraftItemMapping) other).item)); + } + + @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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/OreDictionaryIntegration.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/OreDictionaryIntegration.java new file mode 100644 index 000000000..e29511923 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/OreDictionaryIntegration.java @@ -0,0 +1,97 @@ +/* + * 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_2.wrapper.item; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.oredict.OreDictionary; +import nova.core.event.DictionaryEvent; +import nova.core.item.Item; +import nova.core.item.ItemDictionary; +import nova.core.util.Dictionary; +import nova.core.wrapper.mc.forge.v1_11_2.util.ReflectionUtil; +import nova.internal.core.Game; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +/** + * 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(); + + novaItemDictionary.stream().forEach(entry -> { + entry.getValue().stream() + .map(ItemConverter.instance()::toNative) + .filter(item -> !OreDictionary.getOres(entry.getKey()).contains(item)) + .forEach(item -> OreDictionary.registerOre(entry.getKey(), item)); + }); + + Arrays.stream(OreDictionary.getOreNames()).forEach(key -> { + OreDictionary.getOres(key).stream() + .map(ItemConverter.instance()::getNovaItem) + .filter(item -> !novaItemDictionary.get(key).contains(item)) + .forEach(item -> novaItemDictionary.add(key, item)); + }); + + novaItemDictionary.whenEntryAdded(this::onNovaAdded); + novaItemDictionary.whenEntryRemoved(this::onNovaRemoved); + MinecraftForge.EVENT_BUS.register(this); + } + + private void onNovaAdded(DictionaryEvent.Add event) { + ItemStack nativeStack = ItemConverter.instance().toNative(event.value); + if (!OreDictionary.getOres(event.key).stream().anyMatch(stack -> stack.isItemEqual(nativeStack))) { + OreDictionary.registerOre(event.key, nativeStack); + } + } + + private void onNovaRemoved(DictionaryEvent.Remove event) { + int id = OreDictionary.getOreID(event.key); + ItemStack nativeStack = ItemConverter.instance().toNative(event.value); + Optional toRemove = OreDictionary.getOres(event.key).stream().filter(stack -> stack.isItemEqual(nativeStack)).findFirst(); + + if (toRemove.isPresent()) { + OREDICT_CONTENTS.get(id).remove(toRemove.get()); + } + } + + @SubscribeEvent + public void onForgeAdded(OreDictionary.OreRegisterEvent event) { + Item novaItem = ItemConverter.instance().getNovaItem(event.getOre()); + ItemDictionary novaItemDictionary = Game.itemDictionary(); + if (!novaItemDictionary.get(event.getName()).contains(novaItem)) { + novaItemDictionary.add(event.getName(), novaItem); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/backward/BWItem.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/backward/BWItem.java new file mode 100644 index 000000000..fffdf5d64 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/backward/BWItem.java @@ -0,0 +1,105 @@ +/* + * 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_2.wrapper.item.backward; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import nova.core.component.renderer.StaticRenderer; +import nova.core.item.Item; +import nova.core.retention.Storable; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.forward.IFWItem; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.render.backward.BWBakedModel; + +import java.util.Optional; + +/** + * @author Stan + * @since 3/02/2015. + */ +// TODO: Make this class into a wrapper around an ItemStack instance. +public class BWItem extends Item implements Storable { + private final net.minecraft.item.Item item; + private final int meta; + private final NBTTagCompound tag; + private final NBTTagCompound caps; + + public BWItem(ItemStack itemStack) { + this(itemStack.getItem(), itemStack.getHasSubtypes() ? itemStack.getItemDamage() : 0, itemStack.getTagCompound(), itemStack.serializeNBT().getCompoundTag("ForgeCaps")); + } + + public BWItem(net.minecraft.item.Item item, int meta, NBTTagCompound tag, NBTTagCompound caps) { + this.item = item; + this.meta = meta; + this.tag = tag; + this.caps = caps; + + components.add(new StaticRenderer()) + .onRender(model -> { + model.addChild(new BWBakedModel(Minecraft.getMinecraft().getRenderItem() + .getItemModelMesher().getItemModel(makeItemStack(count())))); + }); + } + + public net.minecraft.item.Item getItem() { + return item; + } + + public int getMeta() { + return meta; + } + + public Optional getTag() { + return Optional.ofNullable(tag); + } + + public Optional getCaps() { + return Optional.ofNullable(caps); + } + + public ItemStack makeItemStack(int stackSize) { + ItemStack result = new ItemStack(item, stackSize, meta, caps); + if (tag != null) { + result.setTagCompound(tag); + } + return result; + } + + @Override + public String getLocalizedName() { + return this.item.getItemStackDisplayName(makeItemStack(count())); + } + + @Override + public String getUnlocalizedName() { + return this.item.getUnlocalizedName(makeItemStack(count())); + } + + @Override + public int getMaxCount() { + return this.item.getItemStackLimit(makeItemStack(count())); + } + + @Override + public String toString() { + return getID(); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/backward/BWItemFactory.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/backward/BWItemFactory.java new file mode 100644 index 000000000..3996caa6a --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/backward/BWItemFactory.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_2.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_2.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter; +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, null)); + + this.item = item; + this.meta = meta; + } + + public net.minecraft.item.Item getItem() { + return item; + } + + public int getMeta() { + return meta; + } + + @Override + public String getUnlocalizedName() { + return this.item.getUnlocalizedName(); + } + + @Override + public Item build(Data data) { + final int meta = (Integer) data.getOrDefault("damage", this.meta); + final NBTTagCompound capsData = DataConverter.instance().toNative(data.get("forgeCaps")); + final NBTTagCompound nbtData; + if (data.containsKey("tag")) + nbtData = DataConverter.instance().toNative(data.get("tag")); + else + nbtData = DataConverter.instance().toNative(data); + + BWItem bwItem = new BWItem(item, meta, nbtData, capsData); + 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 = new Data(); + mcItem.getTag().map(DataConverter.instance()::toNova).ifPresent(caps -> result.put("tag", caps)); + mcItem.getCaps().map(DataConverter.instance()::toNova).ifPresent(caps -> result.put("forgeCaps", caps)); + if (mcItem.getMeta() != meta) { + result.put("damage", mcItem.getMeta()); + } + + return result; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItem.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItem.java new file mode 100644 index 000000000..647062133 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItem.java @@ -0,0 +1,102 @@ +/* + * 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_2.wrapper.item.forward; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ActionResult; +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 nova.core.item.ItemFactory; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.FWCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; + +import java.util.List; +import javax.annotation.Nullable; + +/** + * @author Calclavia + */ +public class FWItem extends net.minecraft.item.Item implements IFWItem { + + public final ItemFactory itemFactory; + + public FWItem(ItemFactory item) { + this.itemFactory = item; + setUnlocalizedName(item.getID()); + setMaxStackSize(item.build().getMaxCount()); + } + + @Override + public ItemFactory getItemFactory() { + return itemFactory; + } + + @Override + @Nullable + public FWCapabilityProvider initCapabilities(ItemStack stack, @Nullable NBTTagCompound nbt) { + return IFWItem.super.initCapabilities(stack, nbt); + } + + @Override + public void addInformation(ItemStack itemStack, EntityPlayer player, List tooltip, boolean advanced) { + IFWItem.super.addInformation(itemStack, player, tooltip, advanced); + } + + @Override + public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { + return IFWItem.super.onItemUse(player.getHeldItem(hand), player, world, pos.getX(), pos.getY(), pos.getZ(), side.ordinal(), hitX, hitY, hitZ); + } + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + return IFWItem.super.onItemRightClick(player.getHeldItem(hand), world, player); + } + + @Override + public int getItemStackLimit(ItemStack stack) { + return IFWItem.super.getItemStackLimit(stack); + } + + @Override + public String getUnlocalizedName() { + return IFWItem.super.getUnlocalizedName(); + } + + @Override + public String getLocalizedName() { + return IFWItem.super.getLocalizedName(); + } + + @Override + public String getUnlocalizedName(ItemStack stack) { + return IFWItem.super.getUnlocalizedName(stack); + } + + @Override + public String getItemStackDisplayName(ItemStack stack) { + return IFWItem.super.getItemStackDisplayName(stack); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItemBlock.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItemBlock.java new file mode 100644 index 000000000..d3b5ce067 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItemBlock.java @@ -0,0 +1,99 @@ +/* + * 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_2.wrapper.item.forward; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ActionResult; +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 nova.core.item.ItemFactory; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.FWCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; + +import java.util.List; +import javax.annotation.Nullable; + +/** + * @author Calclavia + */ +public class FWItemBlock extends net.minecraft.item.ItemBlock implements IFWItem { + + public FWItemBlock(FWBlock block) { + super(block); + } + + @Override + public ItemFactory getItemFactory() { + return ((FWBlock) block).dummy.getItemFactory(); + } + + @Override + @Nullable + public FWCapabilityProvider initCapabilities(ItemStack stack, NBTTagCompound nbt) { + return IFWItem.super.initCapabilities(stack, nbt); + } + + @Override + public void addInformation(ItemStack itemStack, EntityPlayer player, List tooltip, boolean advanced) { + IFWItem.super.addInformation(itemStack, player, tooltip, advanced); + } + + @Override + public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { + return IFWItem.super.onItemUse(player.getHeldItem(hand), player, world, pos.getX(), pos.getY(), pos.getZ(), side.ordinal(), hitX, hitY, hitZ); + } + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + return IFWItem.super.onItemRightClick(player.getHeldItem(hand), world, player); + } + + @Override + public int getItemStackLimit(ItemStack stack) { + return IFWItem.super.getItemStackLimit(stack); + } + + @Override + public String getUnlocalizedName() { + return IFWItem.super.getUnlocalizedName(); + } + + @Override + public String getLocalizedName() { + return IFWItem.super.getLocalizedName(); + } + + @Override + public String getUnlocalizedName(ItemStack stack) { + return IFWItem.super.getUnlocalizedName(stack); + } + + @Override + public String getItemStackDisplayName(ItemStack stack) { + return IFWItem.super.getItemStackDisplayName(stack); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItemCapabilityProvider.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItemCapabilityProvider.java new file mode 100644 index 000000000..129640ca1 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/FWItemCapabilityProvider.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 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_2.wrapper.item.forward; + +import net.minecraftforge.common.capabilities.Capability; +import nova.core.item.Item; +import nova.core.util.Direction; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.FWCapabilityProvider; + +import java.util.Optional; + +/** + * @author ExE Boss + */ +public class FWItemCapabilityProvider extends FWCapabilityProvider { + + private final NovaItem item; + + public FWItemCapabilityProvider(Item item) { + super(item); + this.item = new NovaItem(item); + } + + @Override + public boolean hasCapability(Capability capability, Direction direction) { + return capability == NovaItem.CAPABILITY || super.hasCapability(capability, direction); + } + + @Override + @SuppressWarnings("unchecked") + public Optional getCapability(Capability capability, Direction direction) { + if (capability == NovaItem.CAPABILITY) + return Optional.of((T) item); + return super.getCapability(capability, direction); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/IFWItem.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/IFWItem.java new file mode 100644 index 000000000..af5dad82c --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/IFWItem.java @@ -0,0 +1,102 @@ +/* + * 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_2.wrapper.item.forward; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.world.World; +import nova.core.item.Item; +import nova.core.item.ItemFactory; +import nova.core.language.Translatable; +import nova.core.util.Direction; +import nova.core.util.math.MathUtil; +import nova.core.wrapper.mc.forge.v1_11_2.util.WrapperEvent; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.FWCapabilityProvider; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.backward.BWEntity; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.internal.core.Game; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.List; +import java.util.Optional; +import javax.annotation.Nullable; + +/** + * An interface implemented by {@link FWItem} and {@link FWItemBlock} classes to override Minecraft's item events. + * @author Calclavia + */ +public interface IFWItem extends Translatable { + + ItemFactory getItemFactory(); + + @Nullable + default FWCapabilityProvider initCapabilities(ItemStack stack, @Nullable NBTTagCompound nbt) { + Item item = ItemConverter.instance().popNativeConversion().orElseGet(() -> ItemConverter.instance().getNovaItem(stack)); + WrapperEvent.FWItemInitCapabilities event = new WrapperEvent.FWItemInitCapabilities(item, new FWItemCapabilityProvider(item)); + Game.events().publish(event); + return event.capabilityProvider; + } + + default void addInformation(ItemStack itemStack, EntityPlayer player, List tooltip, boolean advanced) { + Item item = ItemConverter.instance().toNova(itemStack); + item.setCount(itemStack.getCount()).events.publish(new Item.TooltipEvent(Optional.of(new BWEntity(player)), tooltip)); + 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 = ItemConverter.instance().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.PASS; + } + + default ActionResult onItemRightClick(ItemStack itemStack, World world, EntityPlayer player) { + Item item = ItemConverter.instance().toNova(itemStack); + item.events.publish(new Item.RightClickEvent(new BWEntity(player))); + return new ActionResult<>(EnumActionResult.PASS, ItemConverter.instance().updateMCItemStack(itemStack, item)); + } + + default int getItemStackLimit(ItemStack stack) { + return MathUtil.max(ItemConverter.instance().toNova(stack).getMaxCount(), 64); + } + + @Override + default String getUnlocalizedName() { + return getItemFactory().getUnlocalizedName(); + } + + @Override + default String getLocalizedName() { + return getItemFactory().getLocalizedName(); + } + + default String getUnlocalizedName(ItemStack stack) { + return ItemConverter.instance().toNova(stack).getUnlocalizedName(); + } + + default String getItemStackDisplayName(ItemStack stack) { + return ItemConverter.instance().toNova(stack).getLocalizedName(); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/NovaItem.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/NovaItem.java new file mode 100644 index 000000000..8f7d5516a --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/item/forward/NovaItem.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017 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_2.wrapper.item.forward; + +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityInject; +import nova.core.item.Item; +import nova.core.retention.Data; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.NBTStorable; + +/** + * Internal NOVA capability used to make NOVA items persistent. + * + * @author ExE Boss + */ +public class NovaItem implements NBTStorable { + @CapabilityInject(NovaItem.class) + public static Capability CAPABILITY = null; + + public final Item item; + + public NovaItem(Item item) { + this.item = item; + } + + @Override + public void save(Data data) { + item.save(data); + } + + @Override + public void load(Data data) { + item.load(data); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/backward/BWParticle.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/backward/BWParticle.java new file mode 100644 index 000000000..d3aac2bcc --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/backward/BWParticle.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_2.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 nova.core.entity.Entity; + +import java.util.HashMap; +import java.util.Map; + +/** + * 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 Entity { + + 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) { + this.particleID = particleID; + } + + public Particle createParticle(net.minecraft.world.World world) { + //Look up for particle factory and pass it into BWParticle + IParticleFactory particleFactory = FMLClientHandler.instance().getClient().effectRenderer.particleTypes.get(particleID); + Particle particle = particleFactory.createParticle(0, world, 0, 0, 0, 0, 0, 0, 0); + return particle; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/forward/FWParticle.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/forward/FWParticle.java new file mode 100644 index 000000000..18e9b1307 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/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_2.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_2.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11_2.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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/forward/MCParticleTransform.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/forward/MCParticleTransform.java new file mode 100644 index 000000000..088b2bec2 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/particle/forward/MCParticleTransform.java @@ -0,0 +1,71 @@ +/* + * 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_2.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.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +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 WorldConverter.instance().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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/MinecraftRecipeRegistry.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/MinecraftRecipeRegistry.java new file mode 100644 index 000000000..33b9afebc --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/MinecraftRecipeRegistry.java @@ -0,0 +1,369 @@ +/* + * 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_2.wrapper.recipes; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.FurnaceRecipes; +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.item.Item; +import nova.core.recipes.RecipeManager; +import nova.core.recipes.crafting.CraftingRecipe; +import nova.core.recipes.ingredient.ItemIngredient; +import nova.core.recipes.smelting.SmeltingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.util.ReflectionUtil; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.NovaCraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapedRecipeBasic; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapedRecipeOre; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapelessRecipeBasic; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapelessRecipeOre; +import nova.internal.core.Game; + +import java.util.AbstractList; +import java.util.Collection; +import java.util.Collections; +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.Optional; +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.nanoTime(); + + RecipeManager recipeManager = Game.recipes(); + + @SuppressWarnings("unchecked") + 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)); + + Game.logger().info("Initialized recipes in {} ms", (System.nanoTime() - startTime) / 1_000_000); + + 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); + + recipeManager.whenRecipeAdded(SmeltingRecipe.class, this::onNOVASmeltingAdded); + recipeManager.whenRecipeRemoved(SmeltingRecipe.class, this::onNOVASmeltingRemoved); + } + + private CraftingRecipe convert(IRecipe recipe) { + return RecipeConverter.instance().toNova(recipe); + } + + private IRecipe convert(CraftingRecipe recipe) { + return RecipeConverter.instance().toNative(recipe); + } + + @SuppressWarnings("unchecked") + private void onNOVARecipeAdded(RecipeEvent.Add evt) { + CraftingRecipe recipe = evt.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 evt) { + IRecipe minecraftRecipe = forwardWrappers.get(evt.recipe); + + forwardWrappers.remove(evt.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 void onNOVASmeltingAdded(RecipeEvent.Add evt) { + SmeltingRecipe recipe = evt.recipe; + + Collection inputs = recipe.getInput().map(ItemIngredient::getExampleItems).orElse(Collections.emptyList()); + + final Optional output = recipe.getExampleOutput().map(ItemConverter.instance()::toNative); + if (!output.isPresent()) + return; + + inputs.stream().map(ItemConverter.instance()::toNative).forEach(input -> FurnaceRecipes.instance().addSmeltingRecipe(input, output.get(), 0)); + } + + private void onNOVASmeltingRemoved(RecipeEvent.Remove evt) { + SmeltingRecipe recipe = evt.recipe; + + Collection inputs = recipe.getInput().map(ItemIngredient::getExampleItems).orElse(Collections.emptyList()); + @SuppressWarnings("unchecked") + Map smeltingList = FurnaceRecipes.instance().getSmeltingList(); + inputs.stream().map(ItemConverter.instance()::toNative).forEach(input -> smeltingList.remove(input)); + } + + 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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/RecipeConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/RecipeConverter.java new file mode 100644 index 000000000..1b555e354 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/RecipeConverter.java @@ -0,0 +1,300 @@ +/* + * 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_2.wrapper.recipes; + +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.backward.MCCraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.NovaCraftingGrid; +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.item.ItemFactory; +import nova.core.nativewrapper.NativeConverter; +import nova.core.recipes.crafting.CraftingRecipe; +import nova.core.recipes.crafting.ShapedCraftingRecipe; +import nova.core.recipes.crafting.ShapelessCraftingRecipe; +import nova.core.recipes.ingredient.ItemIngredient; +import nova.core.recipes.ingredient.OreItemIngredient; +import nova.core.recipes.ingredient.SpecificItemIngredient; +import nova.core.wrapper.mc.forge.v1_11_2.util.ReflectionUtil; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.NovaCraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapedRecipeBasic; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapedRecipeOre; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapelessRecipeBasic; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.ShapelessRecipeOre; +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 implements NativeConverter { + public static final int TYPE_ADVANCED = 0; + public static final int TYPE_ORE = 1; + public static final int TYPE_BASIC = 2; + + public static RecipeConverter instance() { + return Game.natives().getNative(CraftingRecipe.class, IRecipe.class); + } + + @Override + public Class getNovaSide() { + return CraftingRecipe.class; + } + + @Override + public Class getNativeSide() { + return IRecipe.class; + } + + private int getIngredientType(ItemIngredient ingredient) { + if (ingredient instanceof SpecificItemIngredient) { + return TYPE_BASIC; + } else if (ingredient instanceof OreItemIngredient) { + return TYPE_ORE; + } else { + return TYPE_ADVANCED; + } + } + + private Object getInternal(ItemIngredient ingredient) { + if (ingredient instanceof SpecificItemIngredient) { + return wrapSpecific((SpecificItemIngredient) ingredient); + } else if (ingredient instanceof OreItemIngredient) { + return ((OreItemIngredient) ingredient).getName(); + } + + return null; + } + + private ItemIngredient getIngredient(Object ingredient) { + if (ingredient == null) { + return null; + } else if (ingredient instanceof ItemStack) { + return new SpecificItemIngredient(ItemConverter.instance().toNova((ItemStack) ingredient).getID()); + } else if (ingredient instanceof String) { + return new OreItemIngredient((String) ingredient); + } else if (ingredient instanceof List) { + String oreDictEntry = findOreDictEntryFor((List) ingredient); + if (oreDictEntry == null) { + return null; + } + + return new OreItemIngredient(oreDictEntry); + } else { + return null; + } + } + + private 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 ItemStack wrapSpecific(SpecificItemIngredient ingredient) { + for (Item item : ingredient.getExampleItems()) { + return ItemConverter.instance().toNative(item.getFactory()); + } + + throw new AssertionError("this can't be!"); + } + + private int getRecipeType(ItemIngredient[] ingredients) { + int type = TYPE_BASIC; + for (ItemIngredient ingredient : ingredients) { + type = Math.min(type, getIngredientType(ingredient)); + } + return type; + } + + @Override + public IRecipe toNative(CraftingRecipe recipe) { + if (recipe instanceof ShapedCraftingRecipe) { + return toNative((ShapedCraftingRecipe) recipe); + } else if (recipe instanceof ShapelessCraftingRecipe) { + return toNative((ShapelessCraftingRecipe) recipe); + } else { + return new NovaCraftingRecipe(recipe); + } + } + + public IRecipe toNative(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()]; + List 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 IRecipe toNative(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); + } + } + } + + @Override + public CraftingRecipe toNova(IRecipe recipe) { + ItemStack recipeOutput = recipe.getRecipeOutput(); + if (recipeOutput == null) { + return new MCCraftingRecipe(recipe); + } + Item output = ItemConverter.instance().toNova(recipeOutput); + ItemFactory outputFactory = output.getFactory(); + + 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(outputFactory, (craftingGrid, taggedIngredients, o) -> + Optional.ofNullable(recipe.getCraftingResult(new NovaCraftingGrid(craftingGrid))).map(ItemConverter.instance()::toNova), ingredients); + } else if (recipe instanceof ShapedRecipes) { + ShapedRecipes shaped = (ShapedRecipes) recipe; + + @SuppressWarnings({"unchecked", "rawtypes"}) + 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(outputFactory, (craftingGrid, taggedIngredients, o) -> + Optional.ofNullable(recipe.getCraftingResult(new NovaCraftingGrid(craftingGrid))).map(ItemConverter.instance()::toNova), ingredients, false); + } else if (recipe instanceof ShapedOreRecipe) { + ShapedOreRecipe shaped = (ShapedOreRecipe) recipe; + + int width = ReflectionUtil.getShapedOreRecipeWidth(shaped); + int height = shaped.getRecipeSize() / width; + + @SuppressWarnings({"unchecked", "rawtypes"}) + 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(outputFactory, (craftingGrid, taggedIngredients, o) -> + Optional.ofNullable(recipe.getCraftingResult(new NovaCraftingGrid(craftingGrid))).map(ItemConverter.instance()::toNova), 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(outputFactory, (craftingGrid, taggedIngredients, o) -> + Optional.ofNullable(recipe.getCraftingResult(new NovaCraftingGrid(craftingGrid))).map(ItemConverter.instance()::toNova), ingredients); + } else { + return new MCCraftingRecipe(recipe); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/backward/MCCraftingGrid.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/backward/MCCraftingGrid.java new file mode 100644 index 000000000..dd95327a3 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/backward/MCCraftingGrid.java @@ -0,0 +1,266 @@ +/* + * 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_2.wrapper.recipes.backward; + +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_2.util.ReflectionUtil; +import nova.core.wrapper.mc.forge.v1_11_2.util.WrapUtility; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; + +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[] items; + private ItemStack[] original; + private int itemCount; + + private MCCraftingGrid(InventoryCrafting inventory) { + this.inventory = inventory; + width = height = (int) Math.sqrt(inventory.getSizeInventory()); + items = new nova.core.item.Item[width * height]; + original = new ItemStack[items.length]; + itemCount = 0; + update(); + + Container container = ReflectionUtil.getCraftingContainer(inventory); + if (container != null) { + @SuppressWarnings("unchecked") + List slots = container.inventorySlots; + + EntityPlayer playerOrig = null; + Optional player = Optional.empty(); + + for (Slot slot : slots) { + if (slot instanceof SlotCrafting) { + playerOrig = ReflectionUtil.getCraftingSlotPlayer((SlotCrafting) slot); + player = WrapUtility.getNovaPlayer(playerOrig); + + if (player.isPresent()) { + break; + } + } + } + + this.playerOrig = playerOrig; + this.player = player; + } else { + playerOrig = null; + player = Optional.empty(); + } + } + + private MCCraftingGrid(IInventory inventory, EntityPlayer player) { + this.inventory = inventory; + width = height = (int) Math.sqrt(inventory.getSizeInventory()); + items = new nova.core.item.Item[width * height]; + original = new ItemStack[items.length]; + itemCount = 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()); + items = new nova.core.item.Item[inventory.getSizeInventory()]; + original = new ItemStack[items.length]; + itemCount = 0; + } + + for (int i = 0; i < inventory.getSizeInventory(); i++) { + if (changed(i)) { + //Game.logger().info("Slot {} changed", i); + original[i] = inventory.getStackInSlot(i); + if (inventory.getStackInSlot(i) != null) { + if (items[i] == null) { + itemCount++; + } + + items[i] = ItemConverter.instance().toNova(original[i]); + } else { + if (items[i] != null) { + itemCount--; + } + + items[i] = null; + } + } + } + //Game.logger().info("Num stack count: {}", itemCount); + } + + @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 itemCount; + } + + @Override + public Optional getCrafting(int i) { + return Optional.ofNullable(items[i]); + } + + @Override + public Optional getCrafting(int x, int y) { + return Optional.ofNullable(items[y * width + x]); + } + + @Override + public boolean setCrafting(int x, int y, Optional item) { + //Game.logger().info("setCrafting({}, {}) {}", x, y, item); + + int ix = y * width + x; + if (item.isPresent()) { + if (!item.get().equals(items[ix])) { + inventory.setInventorySlotContents(ix, ItemConverter.instance().toNative(item.get())); + + if (items[ix] == null) { + itemCount++; + } + + items[ix] = item.get(); + } + } else { + itemCount--; + inventory.setInventorySlotContents(ix, null); + items[ix] = null; + } + + return true; + } + + @Override + public boolean setCrafting(int i, Optional item) { + //Game.logger().info("setCrafting({}) {}", i, item); + + if (item.isPresent()) { + if (items[i] == null) { + itemCount++; + } + + inventory.setInventorySlotContents(i, ItemConverter.instance().toNative(item.get())); + items[i] = item.get(); + } else { + if (items[i] == null) { + return true; + } + + itemCount--; + inventory.setInventorySlotContents(i, null); + items[i] = null; + } + + return true; + } + + @Override + public void giveBack(nova.core.item.Item item) { + if (playerOrig != null) { + playerOrig.inventory.addItemStackToInventory(ItemConverter.instance().toNative(item)); + } + } + + @Override + public String getTopology() { + return CraftingGrid.TOPOLOGY_SQUARE; + } + + @Override + public String getType() { + return CraftingGrid.TYPE_CRAFTING; + } + + private boolean changed(int i) { + if (original[i] != inventory.getStackInSlot(i)) { + return true; + } + + if (original[i] != null && items[i].count() != original[i].getCount()) { + return true; + } + + return false; + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/backward/MCCraftingRecipe.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/backward/MCCraftingRecipe.java new file mode 100644 index 000000000..dfa7b437e --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/backward/MCCraftingRecipe.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_2.wrapper.recipes.backward; + +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.forward.NovaCraftingGrid; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.NonNullList; +import nova.core.entity.Entity; +import nova.core.entity.component.Player; +import nova.core.item.Item; +import nova.core.recipes.crafting.CraftingGrid; +import nova.core.recipes.crafting.CraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.world.WorldConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; + +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) { + return recipe.matches(new NovaCraftingGrid(craftingGrid), (net.minecraft.world.World) craftingGrid.getPlayer().map(Player::entity) + .map(Entity::world).map(WorldConverter.instance()::toNative).filter(w -> w instanceof net.minecraft.world.World).orElse(null)); + } + + @Override + public Optional getCraftingResult(CraftingGrid craftingGrid) { + return Optional.of(recipe.getCraftingResult(new NovaCraftingGrid(craftingGrid))).filter(item -> !item.isEmpty()).map(ItemConverter.instance()::toNova); + } + + @Override + public void consumeItems(CraftingGrid craftingGrid) { + NonNullList remainder = recipe.getRemainingItems(new NovaCraftingGrid(craftingGrid)); + for (int i = 0; i < remainder.size(); i++) { + Optional result = Optional.of(remainder.get(i)).filter(item -> !item.isEmpty()).map(ItemConverter.instance()::toNova); + if (!result.isPresent()) { + result = craftingGrid.getCrafting(i).filter(item -> item.count() > 1).map(item -> item.withAmount(item.count() - 1)); + } + craftingGrid.setCrafting(i, result); + } + } + + @Override + public Optional getExampleOutput() { + return Optional.of(recipe.getRecipeOutput()).filter(item -> !item.isEmpty()).map(ItemConverter.instance()::toNova); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingGrid.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingGrid.java new file mode 100644 index 000000000..801a5850c --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingGrid.java @@ -0,0 +1,96 @@ +/* + * 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_2.wrapper.recipes.forward; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import nova.core.item.Item; +import nova.core.recipes.crafting.CraftingGrid; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; + +import java.util.Optional; + +public class NovaCraftingGrid extends InventoryCrafting { + private final CraftingGrid craftingGrid; + + public NovaCraftingGrid(CraftingGrid craftingGrid) { + super(new NovaCraftingGridContainer(craftingGrid), craftingGrid.getWidth(), craftingGrid.getHeight()); + this.craftingGrid = craftingGrid; + } + + @Override + public int getSizeInventory() { + return craftingGrid.size(); + } + + @Override + public ItemStack getStackInSlot(int slot) { + return craftingGrid.getCrafting(slot).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } + + @Override + public ItemStack getStackInRowAndColumn(int x, int y) { + return craftingGrid.getCrafting(x, y).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } + + @Override + public void setInventorySlotContents(int slot, ItemStack item) { + craftingGrid.setCrafting(slot, Optional.of(item).filter(i -> !i.isEmpty()).map(ItemConverter.instance()::toNova)); + } + + @Override + public ItemStack decrStackSize(int slot, int count) { + Optional optionalItem = craftingGrid.getCrafting(slot); + if (!optionalItem.isPresent() || count == 0) { + return null; + } + + Item item = optionalItem.get(); + int added = -item.addCount(-count); + if (item.count() == 0) { + craftingGrid.setCrafting(slot, Optional.empty()); + } + return ItemConverter.instance().toNative(item.withAmount(added)); + } + + @Override + public ItemStack removeStackFromSlot(int slot) { + return craftingGrid.removeCrafting(slot).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } + + @Override + public int getWidth() { + return craftingGrid.getWidth(); + } + + @Override + public int getHeight() { + return craftingGrid.getHeight(); + } + + @Override + public void clear() { + super.clear(); + for (int i = 0; i < craftingGrid.size(); i++) { + craftingGrid.setCrafting(i, Optional.empty()); + } + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingGridContainer.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingGridContainer.java new file mode 100644 index 000000000..97580928d --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/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_2.wrapper.recipes.forward; + +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.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingRecipe.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingRecipe.java new file mode 100644 index 000000000..b647d2751 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/NovaCraftingRecipe.java @@ -0,0 +1,63 @@ +/* + * 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_2.wrapper.recipes.forward; + +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.recipes.crafting.CraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.backward.MCCraftingGrid; + +public class NovaCraftingRecipe implements IRecipe { + private final CraftingRecipe recipe; + + public NovaCraftingRecipe(CraftingRecipe recipe) { + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + return recipe.getCraftingResult(MCCraftingGrid.get(inventory)).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } + + @Override + public int getRecipeSize() { + return 1; + } + + @Override + public ItemStack getRecipeOutput() { + return recipe.getExampleOutput().map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } + + @Override + public NonNullList getRemainingItems(InventoryCrafting inventory) { + return NonNullList.withSize(0, ItemStack.EMPTY); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapedRecipeBasic.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapedRecipeBasic.java new file mode 100644 index 000000000..5c9e63f9f --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapedRecipeBasic.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_2.wrapper.recipes.forward; + +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.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.backward.MCCraftingGrid; + +/** + * @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.getExampleOutput().map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY)); + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + return recipe.getCraftingResult(MCCraftingGrid.get(inventory)).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapedRecipeOre.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapedRecipeOre.java new file mode 100644 index 000000000..db28f85ee --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapedRecipeOre.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 . + */ + +/* + * 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_2.wrapper.recipes.forward; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.oredict.ShapedOreRecipe; +import nova.core.recipes.crafting.ShapedCraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.backward.MCCraftingGrid; + +/** + * @author Stan + */ +public class ShapedRecipeOre extends ShapedOreRecipe { + private final ShapedCraftingRecipe recipe; + + public ShapedRecipeOre(Object[] contents, ShapedCraftingRecipe recipe) { + super(recipe.getExampleOutput().map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY), contents); + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + return recipe.getCraftingResult(MCCraftingGrid.get(inventory)).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapelessRecipeBasic.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapelessRecipeBasic.java new file mode 100644 index 000000000..19068211e --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapelessRecipeBasic.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_2.wrapper.recipes.forward; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.ShapelessRecipes; +import net.minecraft.world.World; +import nova.core.recipes.crafting.ShapelessCraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.backward.MCCraftingGrid; + +import java.util.Arrays; + +/** + * @author Stan + */ +public class ShapelessRecipeBasic extends ShapelessRecipes { + private final ShapelessCraftingRecipe recipe; + + public ShapelessRecipeBasic(ItemStack[] ingredients, ShapelessCraftingRecipe recipe) { + super(recipe.getExampleOutput().map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY), 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) { + return recipe.getCraftingResult(MCCraftingGrid.get(inventory)).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapelessRecipeOre.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapelessRecipeOre.java new file mode 100644 index 000000000..2b56bfd4b --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/recipes/forward/ShapelessRecipeOre.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_2.wrapper.recipes.forward; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.oredict.ShapelessOreRecipe; +import nova.core.recipes.crafting.ShapelessCraftingRecipe; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.recipes.backward.MCCraftingGrid; + +/** + * @author Stan Hebben + */ +public class ShapelessRecipeOre extends ShapelessOreRecipe { + private final ShapelessCraftingRecipe recipe; + + public ShapelessRecipeOre(Object[] ingredients, ShapelessCraftingRecipe recipe) { + super(recipe.getExampleOutput().map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY), ingredients); + this.recipe = recipe; + } + + @Override + public boolean matches(InventoryCrafting inventory, World world) { + return recipe.matches(MCCraftingGrid.get(inventory)); + } + + @Override + public ItemStack getCraftingResult(InventoryCrafting inventory) { + return recipe.getCraftingResult(MCCraftingGrid.get(inventory)).map(ItemConverter.instance()::toNative).orElse(ItemStack.EMPTY); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/backward/BWBakedModel.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/backward/BWBakedModel.java new file mode 100644 index 000000000..ae212ac73 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/backward/BWBakedModel.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2017 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_2.wrapper.render.backward; + +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.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import nova.core.render.Color; +import nova.core.render.model.Face; +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.util.math.MatrixStack; +import nova.core.util.math.TransformUtil; +import nova.core.util.math.Vector3DUtil; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.assets.AssetConverter; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; +import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; +import org.apache.commons.math3.linear.LUDecomposition; +import org.apache.commons.math3.linear.MatrixUtils; +import org.apache.commons.math3.linear.RealMatrix; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +/** + * @author ExE Boss + */ +public class BWBakedModel extends MeshModel { + + @SuppressWarnings("deprecation") + public final IBakedModel wrapped; + + public final VertexFormat format; + + public final Optional blockState; + + public final long rand; + + public BWBakedModel(IBakedModel wrapped) { + this(wrapped, DefaultVertexFormats.ITEM); + } + + public BWBakedModel(IBakedModel wrapped, VertexFormat format) { + this(wrapped, format, Optional.empty(), 0); + } + + public BWBakedModel(IBakedModel wrapped, VertexFormat format, Optional state, long rand) { + this.wrapped = wrapped; + this.format = format; + this.matrix.translate(-0.5, -0.5, -0.5); + this.blockState = state; + this.rand = rand; + + if (!format.getElements().stream().anyMatch(VertexFormatElement::isPositionElement)) + return; // VertexFormat doesn't have a position + + Arrays.stream(Direction.values()) + .map(this::getQuads) + .flatMap(Collection::stream) + .map(this::quadToFace) + .forEachOrdered(faces::add); + } + + @Override + public Set flatten(MatrixStack matrixStack) { + Set models = new HashSet<>(); + + matrixStack.pushMatrix(); + matrixStack.transform(matrix.getMatrix()); + //Create a new model with transformation applied. + MeshModel transformedModel = clone(); + // correct formula for Normal Matrix is transpose(inverse(mat3(model_mat)) + // we have to augemnt that to 4x4 + RealMatrix normalMatrix3x3 = new LUDecomposition(matrixStack.getMatrix().getSubMatrix(0, 2, 0, 2), 1e-5).getSolver().getInverse().transpose(); + RealMatrix normalMatrix = MatrixUtils.createRealMatrix(4, 4); + normalMatrix.setSubMatrix(normalMatrix3x3.getData(), 0, 0); + normalMatrix.setEntry(3, 3, 1); + + transformedModel.faces.stream().forEach(f -> { + f.normal = TransformUtil.transform(f.normal, normalMatrix); + f.vertices.forEach(v -> v.vec = matrixStack.apply(v.vec)); + } + ); + + models.add(transformedModel); + //Flatten child models + matrixStack.pushMatrix(); + matrixStack.translate(0.5, 0.5, 0.5); + models.addAll(children.stream().flatMap(m -> m.flatten(matrixStack).stream()).collect(Collectors.toSet())); + matrixStack.popMatrix().popMatrix(); + return models; + } + + public List getQuads(Direction side) { + return getQuads(DirectionConverter.instance().toNative(side)); + } + + public List getQuads(@Nullable EnumFacing side) { + return wrapped.getQuads(blockState.orElse(null), side, rand); + } + + public Face quadToFace(BakedQuad quad) { + Face face = new Face(); + final VertexFormat format = quad.getFormat(); + + int[] data = quad.getVertexData(); + Optional texture = Optional.ofNullable(quad.getSprite() == null ? wrapped.getParticleTexture() : quad.getSprite()); + + final Optional posElement = ((Collection)format.getElements()).stream() + .filter(VertexFormatElement::isPositionElement) + .findFirst(); + + final Optional uvElement = ((Collection)format.getElements()).stream() + .filter(vfe -> vfe.getUsage() == VertexFormatElement.EnumUsage.UV) + .findFirst(); + + face.texture = texture + .filter(t -> uvElement.isPresent()) + .map(TextureAtlasSprite::getIconName) + .map(ResourceLocation::new) + .map(AssetConverter.instance()::toNovaTexture); + + // `VertexFormat` offsets are for a `ByteBuffer` + // `data` is an int array, so we convert it + + // TODO: support offsets which are not divisible by four + final int posOffset = posElement.map(VertexFormatElement::getIndex).map(i -> i / 4).orElse(-1); + final int uvOffset = uvElement.map(VertexFormatElement::getIndex).map(i -> i / 4).orElse(-1); + final int colorOffset = format.hasColor() ? (format.getColorOffset() / 4) : -1; + final int normalOffset = format.hasNormal() ? (format.getNormalOffset() / 4) : -1; + + for (int i = 0; i < data.length; i += 7) { + Vector3D pos = posElement.isPresent() ? new Vector3D( + Float.intBitsToFloat(data[i + posOffset]), + Float.intBitsToFloat(data[i + posOffset + 1]), + Float.intBitsToFloat(data[i + posOffset + 2])) : Vector3D.ZERO; + + Vector2D uv = uvElement.isPresent() ? new Vector2D( + deinterpolateU(Float.intBitsToFloat(data[i + uvOffset]), texture), + deinterpolateV(Float.intBitsToFloat(data[i + uvOffset + 1]), texture)) : Vector2D.ZERO; + + Vertex vertex = new Vertex(pos, uv); + if (format.hasColor()) { + vertex.color = Color.argb(data[i + colorOffset]); + } + + Optional normal = Optional.empty(); + if (format.hasNormal()) { + int mergedNormal = data[i + normalOffset]; + if (mergedNormal != 0) + normal = Optional.of(new Vector3D(((byte)(mergedNormal & 0xFF)) / 127D, + ((byte)((mergedNormal >> 8) & 0xFF)) / 127D, + ((byte)((mergedNormal >> 16) & 0xFF)) / 127D)); + } + + if (format.hasNormal()) + vertex.normal = normal; + face.drawVertex(vertex); + } + face.normal = Vector3DUtil.calculateNormal(face); + return face; + } + + private double deinterpolateU(double u, Optional texture) { + return u; + } + + private double deinterpolateV(double v, Optional texture) { + return 1 - v; // Why do you change the format with every version, Mojang? + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/backward/BWModel.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/backward/BWModel.java new file mode 100644 index 000000000..c5a46cf6c --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/backward/BWModel.java @@ -0,0 +1,171 @@ +/* + * 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_2.wrapper.render.backward; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +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.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import nova.core.render.model.CustomModel; +import nova.core.render.model.MeshModel; +import nova.core.render.model.Vertex; +import nova.core.render.texture.EntityTexture; +import nova.core.util.math.Vector3DUtil; +import nova.core.wrapper.mc.forge.v1_11_2.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.assets.AssetConverter; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.annotation.Nonnull; + +/** + * BWModel for dynamic rendering + * @author Calclavia + */ +public class BWModel extends MeshModel { + + public void render() { + render(Optional.empty(), Optional.empty()); + } + + public void render(@Nonnull IBlockAccess access) { + render(Optional.of(access), Optional.empty()); + } + + public void render(@Nonnull RenderManager entityRenderManager) { + render(Optional.ofNullable(entityRenderManager.world), Optional.of(entityRenderManager)); + } + + public void render(Optional access, 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 -> { + if (model instanceof MeshModel) { + MeshModel meshModel = (MeshModel) model; + meshModel.faces.forEach(face -> { + boolean isEntityTexture = face.texture.map(t -> t instanceof EntityTexture).orElse(false); + if (entityRenderManager.isPresent() && isEntityTexture) { + entityRenderManager.get().renderEngine.bindTexture(AssetConverter.instance().toNative(face.texture.get())); + } + + final List vertices; + switch (worldRenderer.getDrawMode()) { + case GL11.GL_TRIANGLES: + vertices = new ArrayList<>(3); + vertices.add(face.vertices.get(0)); + vertices.add(face.vertices.get(1)); + vertices.add(face.vertices.get(2)); + break; + case GL11.GL_QUADS: + vertices = new ArrayList<>(4); + vertices.add(face.vertices.get(0)); + vertices.add(face.vertices.get(1)); + vertices.add(face.vertices.get(2)); + if (face.vertices.size() >= 4) + vertices.add(face.vertices.get(3)); + else + vertices.add(face.vertices.get(2)); + break; + default: + vertices = new ArrayList<>(face.vertices); + break; + } + vertices.forEach(v -> { + worldRenderer.getVertexFormat().getElements().forEach(vfe -> { + switch (vfe.getUsage()) { + case POSITION: { + worldRenderer.pos(v.vec.getX(), v.vec.getY(), v.vec.getZ()); + break; + } case NORMAL: { + Vector3D normal = face.normal;//v.normal.orElse(face.normal); + worldRenderer.normal((float)normal.getX(), (float)normal.getY(), (float)normal.getZ()); + break; + } case COLOR: { + worldRenderer.color(v.color.red(), v.color.green(), v.color.blue(), v.color.alpha()); + break; + } case UV: { + if (vfe.getIndex() == 0) { + if (entityRenderManager.isPresent() && isEntityTexture) { + //We're not working on an atlas, so just do... this. + worldRenderer.tex(v.uv.getX(), v.uv.getY()); + } else { + TextureAtlasSprite tex = face.texture.map(RenderUtility.instance::getTexture) + .orElseGet(Minecraft.getMinecraft().getTextureMapBlocks()::getMissingSprite); + worldRenderer.tex(tex.getInterpolatedU(16 * v.uv.getX()), tex.getInterpolatedV(16 * v.uv.getY())); + } + } else if (vfe.getIndex() == 1) { + if (face.getBrightness() >= 0) { + worldRenderer.lightmap((int)(face.getBrightness() * 15), (int)(face.getBrightness() * 11)); + } else if(access.isPresent()) { + // Determine nearest adjacent block. + Vector3D nearestPos = Vector3DUtil.floor(face.getCenter().add(face.normal.scalarMultiply(0.05))); + BlockPos blockPos = VectorConverter.instance().toNative(nearestPos); + IBlockState state = access.get().getBlockState(blockPos); + int brightness = state.getPackedLightmapCoords(access.get(), blockPos); + + // TODO: Add Ambient Occlusion + /* + int aoBrightnessXYNN = state.getPackedLightmapCoords(access.get(), blockPos.east()); + int aoBrightnessYZNN = state.getPackedLightmapCoords(access.get(), blockPos.north()); + int aoBrightnessYZNP = state.getPackedLightmapCoords(access.get(), blockPos.south()); + int aoBrightnessXYPN = state.getPackedLightmapCoords(access.get(), blockPos.west()); + + int brightnessTopLeft = getAoBrightness(aoBrightnessXYZNNP, aoBrightnessXYNN, aoBrightnessYZNP, i1); + int brightnessTopRight = getAoBrightness(aoBrightnessYZNP, aoBrightnessXYZPNP, aoBrightnessXYPN, i1); + int brightnessBottomRight = getAoBrightness(aoBrightnessYZNN, aoBrightnessXYPN, aoBrightnessXYZPNN, i1); + int brightnessBottomLeft = getAoBrightness(aoBrightnessXYNN, aoBrightnessXYZNNN, aoBrightnessYZNN, i1); + */ + + worldRenderer.lightmap((brightness >>> 20) & 0xFFFF, (brightness >>> 4) & 0xFFFF); + } else { + worldRenderer.lightmap(15, 11); + } + } + break; + } + } + }); + worldRenderer.endVertex(); + }); + }); + } else if (model instanceof CustomModel) { + CustomModel customModel = (CustomModel) model; + customModel.render.accept(customModel); + } + } + ); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWEmptyModel.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWEmptyModel.java new file mode 100644 index 000000000..5acdc0d79 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWEmptyModel.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_2.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.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +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 { + + /** The singleton instance of an empty model. */ + public static final FWEmptyModel INSTANCE = new FWEmptyModel(); + + private FWEmptyModel() {} + + //Item rendering + @Override + public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity) { + return this; + } + + @Override + public List getQuads(IBlockState state, EnumFacing side, long rand) { + return Collections.emptyList(); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartBlockModel.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartBlockModel.java new file mode 100644 index 000000000..8281360a9 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartBlockModel.java @@ -0,0 +1,115 @@ +/* + * 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_2.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.ItemCameraTransforms; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; +import nova.core.block.Block; +import nova.core.component.renderer.Renderer; +import nova.core.component.renderer.StaticRenderer; +import nova.core.item.Item; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.VectorConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.block.forward.FWBlock; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.render.backward.BWModel; +import org.lwjgl.util.vector.Vector3f; + +import java.util.List; +import java.util.Optional; + +/** + * Generates a smart model based on a NOVA Model + * @author Calclavia + */ +public class FWSmartBlockModel extends FWSmartModel implements IBakedModel { + + private final Block block; + private final Optional item; + + public FWSmartBlockModel(Block block) { + this(block, Optional.empty()); + } + + public FWSmartBlockModel(Block block, Item item) { + this(block, Optional.of(item)); + } + + @SuppressWarnings("deprecation") + public FWSmartBlockModel(Block block, Optional item) { + this.block = block; + this.item = item; + // Change the default transforms to the default full Block transforms + this.itemCameraTransforms = new ItemCameraTransforms( + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(75, 225, 0), new Vector3f(0, 0.1875f, 0.03125f), new Vector3f(0.375f, 0.375f, 0.375f)), // Third Person (Left) + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(75, 45, 0), new Vector3f(0, 0.1875f, 0.03125f), new Vector3f(0.375f, 0.375f, 0.375f)), // Third Person (Right) + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(0, 225, 0), new Vector3f(0, 0, 0), new Vector3f(0.4f, 0.4f, 0.4f)), // First Person (Left) + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(0, 45, 0), new Vector3f(0, 0, 0), new Vector3f(0.4f, 0.4f, 0.4f)), // First Person (Right) + net.minecraft.client.renderer.block.model.ItemTransformVec3f.DEFAULT, // Head + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(30, 225, 0), new Vector3f(0, 0, 0), new Vector3f(0.625f, 0.625f, 0.625f)), // GUI + net.minecraft.client.renderer.block.model.ItemTransformVec3f.DEFAULT, // Ground + net.minecraft.client.renderer.block.model.ItemTransformVec3f.DEFAULT);// Fixed + } + + //Item rendering + @Override + public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity) { + Item item = ItemConverter.instance().toNova(stack); + + if (item.components.has(Renderer.class) || block.components.has(Renderer.class)) { + return new FWSmartBlockModel(block, item); + } + + return FWEmptyModel.INSTANCE; + } + + @Override + @SuppressWarnings("deprecation") + public List getQuads(IBlockState state, EnumFacing side, long rand) { + final Block block; + if (state != null) { + FWBlock fwBlock = (FWBlock) state.getBlock(); + block = fwBlock.getBlockInstance(fwBlock.lastExtendedWorld, VectorConverter.instance().toNova(fwBlock.lastExtendedStatePos)); + } else { + block = this.block; + } + + BWModel model = new BWModel(); + model.matrix.translate(0.5, 0.5, 0.5); + + if (item.isPresent()) { + if (item.get().components.has(Renderer.class)) { + item.get().components.getSet(Renderer.class).forEach(r -> r.onRender.accept(model)); + } else { + block.components.getSet(Renderer.class).forEach(r -> r.onRender.accept(model)); + } + } else { + block.components.getOp(StaticRenderer.class).ifPresent(r -> r.onRender.accept(model)); + } + + return modelToQuads(model, item.map(Item::colorMultiplier)); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartItemModel.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartItemModel.java new file mode 100644 index 000000000..c40463c17 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartItemModel.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_2.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.ItemCameraTransforms; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; +import nova.core.component.renderer.Renderer; +import nova.core.item.Item; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.item.ItemConverter; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.render.backward.BWModel; +import org.lwjgl.util.vector.Vector3f; + +import java.util.List; + +/** + * Generates a smart model based on a NOVA Model + * @author Calclavia + */ +@SuppressWarnings("deprecation") +public class FWSmartItemModel extends FWSmartModel implements IBakedModel { + + private final Item item; + + @SuppressWarnings("deprecation") + public FWSmartItemModel(Item item) { + this.item = item; + // Change the default transforms to the default Item transforms + this.itemCameraTransforms = new ItemCameraTransforms( + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(0, -90, -130), new Vector3f(0, 1f / 24f, -2.75f / 16f), new Vector3f(0.9f, 0.9f, 0.9f)), // Third Person (Left) + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(0, -90, -130), new Vector3f(0, 1f / 24f, -2.75f / 16f), new Vector3f(0.9f, 0.9f, 0.9f)), // Third Person (Right) + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(0, -135, 25), new Vector3f(0, 0.25f, 0.125f), new Vector3f(1.7f, 1.7f, 1.7f)), // First Person (Left) + new net.minecraft.client.renderer.block.model.ItemTransformVec3f(new Vector3f(0, -135, 25), new Vector3f(0, 0.25f, 0.125f), new Vector3f(1.7f, 1.7f, 1.7f)), // First Person (Rigth) + net.minecraft.client.renderer.block.model.ItemTransformVec3f.DEFAULT, // Head + net.minecraft.client.renderer.block.model.ItemTransformVec3f.DEFAULT, // new ItemTransformVec3f(new Vector3f(-30, 135, 0), new Vector3f(), new Vector3f(1.6F, 1.6F, 1.6F)), // GUI + net.minecraft.client.renderer.block.model.ItemTransformVec3f.DEFAULT, // Ground + net.minecraft.client.renderer.block.model.ItemTransformVec3f.DEFAULT);// Fixed + } + + //Item rendering + @Override + public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity) { + Item item = ItemConverter.instance().toNova(stack); + + if (item.components.has(Renderer.class)) { + return new FWSmartItemModel(item); + } + + return FWEmptyModel.INSTANCE; + } + + @Override + @SuppressWarnings("deprecation") + public List getQuads(IBlockState state, EnumFacing side, long rand) { + BWModel model = new BWModel(); + model.matrix.translate(0.5, 0.5, 0.5); + item.components.getSet(Renderer.class).forEach(r -> r.onRender.accept(model)); + return modelToQuads(model, item.colorMultiplier()); + } + + @Override + public boolean isGui3d() { + return item.components.has(Renderer.class); + } +} diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartModel.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartModel.java new file mode 100644 index 000000000..c3f242795 --- /dev/null +++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/render/forward/FWSmartModel.java @@ -0,0 +1,188 @@ +/* + * 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_2.wrapper.render.forward; + +import com.google.common.primitives.Ints; +import net.minecraft.client.Minecraft; +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.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import nova.core.render.Color; +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.util.math.MathUtil; +import nova.core.wrapper.mc.forge.v1_11_2.render.RenderUtility; +import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Generates a smart model based on a NOVA Model + * @author Calclavia + */ +@SuppressWarnings("deprecation") +public abstract class FWSmartModel implements IBakedModel { + + protected static final VertexFormat NOVA_VERTEX_FORMAT = DefaultVertexFormats.ITEM; + + protected final VertexFormat format; + // Default item transforms. Can be changed in subclasses. + protected ItemCameraTransforms itemCameraTransforms = ItemCameraTransforms.DEFAULT; + private final FWOverrideList overrides; + + protected FWSmartModel(VertexFormat format) { + this.format = format; + this.overrides = new FWOverrideList(); + } + + public FWSmartModel() { + this(NOVA_VERTEX_FORMAT); + } + + public static int[] vertexToInts(Vertex vertex, TextureAtlasSprite texture, Vector3D normal) { + // TODO: Possibly support arbitrary `VertexFormat` +// if (vertex.normal.isPresent()) +// normal = vertex.normal.get(); + 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())), + ((((byte)(normal.getX() * 127)) & 0xFF) | + ((((byte)(normal.getY() * 127)) & 0xFF) << 8) | + ((((byte)(normal.getZ() * 127)) & 0xFF) << 16)) + }; + } + + public abstract IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity); + + protected List modelToQuads(Model modelIn) { + return modelToQuads(modelIn, Optional.empty()); + } + + protected List modelToQuads(Model modelIn, Color colorMultiplier) { + return modelToQuads(modelIn, Optional.of(colorMultiplier)); + } + + protected List modelToQuads(Model modelIn, Optional colorMultiplier) { + return modelIn + .flatten() + .stream() + .flatMap( + model -> { + if (model instanceof MeshModel) { + MeshModel meshModel = (MeshModel) model; + return meshModel.faces + .stream() + .filter(f -> f.vertices.size() > 2) + .map( + face -> { + TextureAtlasSprite texture = face.texture.map(RenderUtility.instance::getTexture) + .orElseGet(Minecraft.getMinecraft().getTextureMapBlocks()::getMissingSprite); + List vertexData = face.vertices + .stream() + .map(v -> { + colorMultiplier.ifPresent(c -> v.color = v.color.multiply(c)); + return v; + }) + .map(v -> vertexToInts(v, texture, face.normal)) + .collect(Collectors.toList()); + + if (vertexData.size() < 4) + vertexData.add(vertexData.get(vertexData.size() - 1)); + + int[] data = Ints.concat(vertexData.toArray(new int[][] {})); + //TODO: The facing might be wrong + return new BakedQuad(Arrays.copyOf(data, MathUtil.min(data.length, format.getNextOffset())), -1, + DirectionConverter.instance().toNative(Direction.fromVector(face.normal)), texture, 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 Minecraft.getMinecraft().getTextureMapBlocks().getMissingSprite(); + } + + @Override + @Deprecated + public ItemCameraTransforms getItemCameraTransforms() { + return itemCameraTransforms; + } + + @Override + public final ItemOverrideList getOverrides() { + return overrides; + } + + private final class FWOverrideList extends ItemOverrideList { + private FWOverrideList() { + super(Collections.emptyList()); + } + + @Override + public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity) { + return FWSmartModel.this.handleItemState(originalModel, stack, world, entity); + } + } +} diff --git a/minecraft/1.11.2/src/main/resources/META-INF/nova_at.cfg b/minecraft/1.11.2/src/main/resources/META-INF/nova_at.cfg new file mode 100644 index 000000000..8602ae65f --- /dev/null +++ b/minecraft/1.11.2/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.2/src/main/resources/assets/nova/textures/NOVA.png b/minecraft/1.11.2/src/main/resources/assets/nova/textures/NOVA.png new file mode 100644 index 000000000..1f42e113c Binary files /dev/null and b/minecraft/1.11.2/src/main/resources/assets/nova/textures/NOVA.png differ diff --git a/minecraft/1.11.2/src/main/resources/fmlbranding.properties b/minecraft/1.11.2/src/main/resources/fmlbranding.properties new file mode 100644 index 000000000..bc328e1a2 --- /dev/null +++ b/minecraft/1.11.2/src/main/resources/fmlbranding.properties @@ -0,0 +1 @@ +fmlbranding=NOVA ${version} diff --git a/minecraft/1.11.2/src/main/resources/mcmod.info b/minecraft/1.11.2/src/main/resources/mcmod.info new file mode 100644 index 000000000..6bb0881bf --- /dev/null +++ b/minecraft/1.11.2/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": "${version}", + "mcversion": "${mcversion}", + "url": "https://novaapi.net/", + "updateUrl": "", + "authorList": [ "calclavia", "RX14", "AEnterprise", "magik6k", "Shadowfacts", "ExE Boss" ], + "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.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/NovaLauncherTest.java b/minecraft/1.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/NovaLauncherTest.java new file mode 100644 index 000000000..61175144f --- /dev/null +++ b/minecraft/1.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/launcher/NovaLauncherTest.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_2.launcher; + +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.ClientModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.GameInfoModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.KeyModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.LanguageModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.SaveModule; +import nova.core.wrapper.mc.forge.v1_11_2.depmodules.TickerModule; +import nova.internal.core.Game; +import nova.internal.core.bootstrap.DependencyInjectionEntryPoint; +import nova.wrappertests.AbstractNovaLauncherTest; +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 AbstractNovaLauncherTest { + + @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 use a fake. + 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.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/DirectionConverterTest.java b/minecraft/1.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/DirectionConverterTest.java new file mode 100644 index 000000000..54c536223 --- /dev/null +++ b/minecraft/1.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/DirectionConverterTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017 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_2.wrapper; + +import net.minecraft.util.EnumFacing; +import nova.core.util.Direction; +import org.junit.Before; +import org.junit.Test; + +import static nova.testutils.NovaAssertions.assertThat; + +/** + * Used to test {@link DirectionConverter}. + * + * @author ExE Boss + */ +public class DirectionConverterTest { + + DirectionConverter converter; + + @Before + public void setUp() { + converter = new DirectionConverter(); + } + + @Test + public void testToNova() { + assertThat(converter.toNova(EnumFacing.DOWN)).isEqualTo(Direction.DOWN); + assertThat(converter.toNova(EnumFacing.UP)).isEqualTo(Direction.UP); + assertThat(converter.toNova(EnumFacing.NORTH)).isEqualTo(Direction.NORTH); + assertThat(converter.toNova(EnumFacing.SOUTH)).isEqualTo(Direction.SOUTH); + assertThat(converter.toNova(EnumFacing.WEST)).isEqualTo(Direction.WEST); + assertThat(converter.toNova(EnumFacing.EAST)).isEqualTo(Direction.EAST); + assertThat(converter.toNova(null)).isEqualTo(Direction.UNKNOWN); + } + + @Test + public void testToNative() { + assertThat(converter.toNative(Direction.DOWN)).isEqualTo(EnumFacing.DOWN); + assertThat(converter.toNative(Direction.UP)).isEqualTo(EnumFacing.UP); + assertThat(converter.toNative(Direction.NORTH)).isEqualTo(EnumFacing.NORTH); + assertThat(converter.toNative(Direction.SOUTH)).isEqualTo(EnumFacing.SOUTH); + assertThat(converter.toNative(Direction.WEST)).isEqualTo(EnumFacing.WEST); + assertThat(converter.toNative(Direction.EAST)).isEqualTo(EnumFacing.EAST); + assertThat(converter.toNative(Direction.UNKNOWN)).isNull(); + } +} diff --git a/minecraft/1.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/VectorConverterTest.java b/minecraft/1.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/VectorConverterTest.java new file mode 100644 index 000000000..39c4bfb0d --- /dev/null +++ b/minecraft/1.11.2/src/test/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/VectorConverterTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017 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_2.wrapper; + +import net.minecraft.util.math.BlockPos; +import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; +import org.junit.Before; +import org.junit.Test; + +import static nova.testutils.NovaAssertions.assertThat; + +/** + * Used to test {@link VectorConverter}. + * + * @author ExE Boss + */ +public class VectorConverterTest { + + VectorConverter converter; + + @Before + public void setUp() { + converter = new VectorConverter(); + } + + @Test + public void testToNova() { + for (int x = -1; x <= 1; x++) + for (int y = -1; y <= 1; y++) + for (int z = -1; z <= 1; z++) + assertThat(converter.toNova(new BlockPos(x, y, z))).isEqualTo(new Vector3D(x, y, z)); + } + + @Test + @SuppressWarnings("unchecked") + public void testToNative() { + for (int x = -1; x <= 1; x++) + for (int y = -1; y <= 1; y++) + for (int z = -1; z <= 1; z++) + assertThat(converter.toNative(new Vector3D(x, y, z))).isEqualTo(new BlockPos(x, y, z)); + } +} diff --git a/settings.gradle b/settings.gradle index ddb6052d4..e6f6c4236 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ rootProject.name = "NOVA-Core" +include "minecraft:1.11.2" include "minecraft:1.8" include "minecraft:1.7.10"