Browse Source

first commit

1.10
Adrian Siekierka 2 years ago
commit
1cbcab6a07
30 changed files with 3198 additions and 0 deletions
  1. 22
    0
      Jenkinsfile
  2. 1
    0
      README.md
  3. 2
    0
      TODO.md
  4. 87
    0
      build.gradle
  5. 3
    0
      gradle.properties
  6. BIN
      gradle/wrapper/gradle-wrapper.jar
  7. 6
    0
      gradle/wrapper/gradle-wrapper.properties
  8. 164
    0
      gradlew
  9. 73
    0
      src/main/java/pl/asie/ucw/CommandUCWDebug.java
  10. 183
    0
      src/main/java/pl/asie/ucw/UCWBlockRule.java
  11. 41
    0
      src/main/java/pl/asie/ucw/UCWCompatUtils.java
  12. 199
    0
      src/main/java/pl/asie/ucw/UCWFakeResourcePack.java
  13. 205
    0
      src/main/java/pl/asie/ucw/UCWMagic.java
  14. 337
    0
      src/main/java/pl/asie/ucw/UCWObjectFactory.java
  15. 213
    0
      src/main/java/pl/asie/ucw/UCWProxyClient.java
  16. 26
    0
      src/main/java/pl/asie/ucw/UCWProxyCommon.java
  17. 196
    0
      src/main/java/pl/asie/ucw/UnlimitedChiselWorks.java
  18. 324
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/abyssalcraft.json
  19. 74
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/ae2.json
  20. 63
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/biomesoplenty.json
  21. 242
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/botania.json
  22. 106
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/extratrees.json
  23. 114
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/forestry.json
  24. 102
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/integrateddynamics.json
  25. 38
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/natura.json
  26. 105
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/quark.json
  27. 63
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/rustic.json
  28. 186
    0
      src/main/resources/assets/unlimitedchiselworks/ucwdefs/traverse.json
  29. 16
    0
      src/main/resources/mcmod.info
  30. 7
    0
      src/main/resources/pack.mcmeta

+ 22
- 0
Jenkinsfile View File

@@ -0,0 +1,22 @@
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'rm -f private.gradle'
sh './gradlew setupCiWorkspace clean build'
archive 'build/libs/*jar'
}
}
stage('Deploy') {
steps {
withCredentials([file(credentialsId: 'privateGradleNoSnapshot', variable: 'PRIVATEGRADLE')]) {
sh '''
cp "$PRIVATEGRADLE" private.gradle
./gradlew upload
'''
}
}
}
}
}

+ 1
- 0
README.md View File

@@ -0,0 +1 @@
This is the GitHub repository for Unlimited Chisel Works.

+ 2
- 0
TODO.md View File

@@ -0,0 +1,2 @@
* Some blocks require manual tweaking:
* Quark Biotite

+ 87
- 0
build.gradle View File

@@ -0,0 +1,87 @@
buildscript {
repositories {
jcenter()
maven { url = "http://files.minecraftforge.net/maven" }
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath "gradle.plugin.net.minecrell:licenser:0.3"
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'net.minecrell.licenser'
version = "0.1.0"
group = "pl.asie.ucw"
archivesBaseName = "UnlimitedChiselWorks"
sourceCompatibility = targetCompatibility = '1.8'
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
}
if (System.getenv("BUILD_NUMBER") != null)
version += ".${System.getenv("BUILD_NUMBER")}"
configurations {
deploy
}
dependencies {
deploy 'org.apache.maven.wagon:wagon-ssh:2.10'
}
minecraft {
version = "1.12.1-14.22.1.2481"
runDir = "run"
mappings = "snapshot_20170915"
}
repositories {
maven {
url "http://maven.tterrag.com/"
}
}
sourceSets {
main {
resources {
srcDirs += 'docs'
}
}
}
license {
sourceSets = [project.sourceSets.main]
header = project.file("docs/licenses/LICENSE")
ignoreFailures = true
exclude '**/*.lang'
exclude '**/*.info'
exclude '**/*.mcmeta'
}
dependencies {
deobfCompile "team.chisel:Chisel:MC1.12-0.0.14.18"
deobfCompile "team.chisel.ctm:CTM:MC1.12-0.2.2.7"
}
processResources {
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
expand 'version':project.version, 'mcversion':project.minecraft.version
}
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
if (file('private.gradle').exists()) {
apply from: 'private.gradle'
}

+ 3
- 0
gradle.properties View File

@@ -0,0 +1,3 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G

BIN
gradle/wrapper/gradle-wrapper.jar View File


+ 6
- 0
gradle/wrapper/gradle-wrapper.properties View File

@@ -0,0 +1,6 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip

+ 164
- 0
gradlew View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash

##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
echo "$*"
}

die ( ) {
echo
echo "$*"
echo
exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac

# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`

# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option

if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

+ 73
- 0
src/main/java/pl/asie/ucw/CommandUCWDebug.java View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class CommandUCWDebug extends CommandBase {
@Override
public String getName() {
return "ucw_debug";
}

@Override
public String getUsage(ICommandSender sender) {
return "no, don't";
}

@Override
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
if (sender instanceof EntityPlayerMP) {
World world = sender.getEntityWorld();
BlockPos pos = sender.getPosition();
for (UCWBlockRule rule : UnlimitedChiselWorks.BLOCK_RULES) {
for (UCWObjectFactory factory : rule.objectFactories.valueCollection()) {
BlockPos.MutableBlockPos posCopy = new BlockPos.MutableBlockPos(pos);
NonNullList<ItemStack> stackList = NonNullList.create();
factory.item.getSubItems(CreativeTabs.SEARCH, stackList);

world.setBlockState(posCopy, factory.base);
posCopy.move(EnumFacing.EAST);

for (ItemStack stack : stackList) {
try {
world.setBlockState(posCopy, factory.block.getStateFromMeta(stack.getMetadata()));
posCopy.move(EnumFacing.EAST);
} catch (Exception e) {

}
}

pos = pos.south();
}
}
}
}
}

+ 183
- 0
src/main/java/pl/asie/ucw/UCWBlockRule.java View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.registries.IForgeRegistry;

import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.util.*;

public class UCWBlockRule {
private static final Method WITH_PROPERTY = ReflectionHelper.findMethod(IBlockState.class, "withProperty", "func_177226_a", IProperty.class, Comparable.class);
protected final List<IBlockState> from;
protected final List<IBlockState> through;
protected final List<IBlockState> basedUpon;
protected @Nonnull final Block fromBlock, throughBlock, basedUponBlock;
protected final TIntObjectMap<UCWObjectFactory> objectFactories = new TIntObjectHashMap<>();
protected final String prefix;
protected final String group;
protected final int fromCount;

public UCWBlockRule(JsonObject object) throws Exception {
from = parseStateList(object.get("from").getAsJsonObject(), true);
through = parseStateList(object.get("through").getAsJsonObject(), true);
basedUpon = parseStateList(object.get("based_upon").getAsJsonObject(), false);
fromBlock = getBlock(from);
throughBlock = getBlock(through);
basedUponBlock = getBlock(basedUpon);

int fc = 0;
for (IBlockState state : from) {
if (state != null) fc++;
}
fromCount = fc;

group = object.has("group") ? object.get("group").getAsString() : fromBlock.getRegistryName().toString();

String s1 = throughBlock.getRegistryName().toString().trim().replaceAll("[^A-Za-z0-9]", "_");
String s2 = fromBlock.getRegistryName().toString().trim().replaceAll("[^A-Za-z0-9]", "_");
prefix = s1 + "_" + s2 + "_";
for (int i = 0; i < from.size(); i++) {
if (from.get(i) != null) {
IBlockState state = from.get(i);
String s = prefix + i;

objectFactories.put(i, new UCWObjectFactory(this, state, new ResourceLocation(UnlimitedChiselWorks.MODID, s)));
}
}
}

@Override
public int hashCode() {
return 7 * (17 * from.hashCode() + through.hashCode()) + basedUpon.hashCode();
}

@Override
public boolean equals(Object o) {
if (o instanceof UCWBlockRule) {
UCWBlockRule other = (UCWBlockRule) o;
return other.from.equals(from) && other.through.equals(through) && other.basedUpon.equals(basedUpon);
}

return false;
}

@Override
public String toString() {
return "[UCWBlockRule: " + fromBlock.getRegistryName() + " -> " + throughBlock.getRegistryName() + " (" + basedUponBlock.getRegistryName() + ")]";
}

public boolean isValid() {
return from.size() > 0 && through.size() > 0 && (basedUpon.size() == 1 || basedUpon.size() == through.size());
}

public void registerBlocks(IForgeRegistry<Block> blocks) {
for (UCWObjectFactory objectFactory : objectFactories.valueCollection()) {
blocks.register(objectFactory.block);
}
}

public void registerItems(IForgeRegistry<Item> blocks) {
for (UCWObjectFactory objectFactory : objectFactories.valueCollection()) {
blocks.register(objectFactory.item);
}
}

private static Block getBlock(List<IBlockState> list) {
for (IBlockState state : list) {
if (state != null) {
return state.getBlock();
}
}
return Blocks.AIR;
}

private static List<IBlockState> parseStateList(JsonObject object, boolean orderMatters) throws Exception {
if (object.has("block")) {
ResourceLocation blockLoc = new ResourceLocation(object.get("block").getAsString());
if (ForgeRegistries.BLOCKS.containsKey(blockLoc)) {
Block block = ForgeRegistries.BLOCKS.getValue(blockLoc);
if (orderMatters) {
Set<IBlockState> states = Sets.newHashSet(block.getBlockState().getValidStates());
List<IBlockState> stateList = new ArrayList<>(16);

for (int i = 0; i < 16; i++) {
stateList.add(null);
try {
IBlockState state = block.getStateFromMeta(i);
if (states.remove(state)) {
stateList.set(i, state);
}
} catch (Exception e) {
e.printStackTrace();
/* ... */
}
}

return stateList;
} else {
return block.getBlockState().getValidStates();
}
} else {
return Collections.emptyList();
}
} else if (object.has("state")) {
String[] stateStr = object.get("state").getAsString().split("#", 2);
ResourceLocation blockLoc = new ResourceLocation(stateStr[0]);
if (ForgeRegistries.BLOCKS.containsKey(blockLoc)) {
Block block = ForgeRegistries.BLOCKS.getValue(blockLoc);
IBlockState state = block.getDefaultState();
if (stateStr.length > 1) {
for (String stateParam : stateStr[1].split(",")) {
String[] stateKv = stateParam.split("=", 2);
if (stateKv.length > 1) {
IProperty property = block.getBlockState().getProperty(stateKv[0]);
if (property != null) {
com.google.common.base.Optional optValue = property.parseValue(stateKv[1]);
if (optValue.isPresent()) {
// TODO: !?!?
state = (IBlockState) WITH_PROPERTY.invoke(state, property, optValue.get());
}
}
}
}
}
return Collections.singletonList(state);
} else {
return Collections.emptyList();
}
} else {
return Collections.emptyList();
}
}
}

+ 41
- 0
src/main/java/pl/asie/ucw/UCWCompatUtils.java View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.common.event.FMLInterModComms;

public final class UCWCompatUtils {
private UCWCompatUtils() {

}

public static void addChiselVariation(String group, ItemStack stack) {
NBTTagCompound tag = new NBTTagCompound();
NBTTagCompound itemTag = new NBTTagCompound();
stack.writeToNBT(itemTag);

tag.setString("group", group);
tag.setTag("stack", itemTag);

FMLInterModComms.sendMessage("chisel", "add_variation", tag);
}
}

+ 199
- 0
src/main/java/pl/asie/ucw/UCWFakeResourcePack.java View File

@@ -0,0 +1,199 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
import com.google.gson.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.client.resources.data.IMetadataSection;
import net.minecraft.client.resources.data.MetadataSerializer;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation;

import javax.annotation.Nullable;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UCWFakeResourcePack implements IResourcePack, IResourceManagerReloadListener {
public static final UCWFakeResourcePack INSTANCE = new UCWFakeResourcePack();

private final Map<ResourceLocation, byte[]> data = new HashMap<>();
private final Map<ResourceLocation, JsonElement> jsonCache = new HashMap<>();
private final Set<String> domains = ImmutableSet.of("ucw_generated");

private UCWFakeResourcePack() {

}

public JsonElement parseJsonElement(String[] str, JsonElement element) {
if (element.isJsonObject()) {
JsonObject parent = element.getAsJsonObject();
JsonObject object = new JsonObject();
for (Map.Entry<String, JsonElement> entry : parent.entrySet()) {
object.add(entry.getKey(), parseJsonElement(str, entry.getValue()));
}
return object;
} else if (element.isJsonArray()) {
JsonArray parent = element.getAsJsonArray();
JsonArray array = new JsonArray();
for (JsonElement element1 : parent) {
array.add(parseJsonElement(str, element1));
}
return array;
} else if (!element.isJsonNull()) {
String s = element.getAsString();
if (s != null && s.startsWith(str[1] + ":")) {
String ns = "ucw_generated:ucw_ucw_" + str[0] + "/" + s.replaceFirst(":", "/");
System.out.println(s + " -> " + ns);
return new JsonPrimitive(ns);
} else {
return element;
}
} else {
return element;
}
}

private String[] getStr(ResourceLocation location) {
String path = location.getResourcePath();
if (path.contains(".png")) {
return null;
}
Matcher m = Pattern.compile("ucw_ucw_([A-Za-z0-9_]+)/([a-z]+)").matcher(path);
String[] str = new String[] {
"",
"",
""
};

if (m.find()) {
str[0] = m.group(1);
str[1] = m.group(2);
}

String nonProxyPath = path.replaceAll("ucw_ucw_[A-Za-z0-9_]+/[a-z]+/", "");
str[2] = nonProxyPath;
return str;
}

@Override
public InputStream getInputStream(ResourceLocation location) throws IOException {
if (!data.containsKey(location)) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

String[] str = getStr(location);
JsonElement element;
ResourceLocation nonProxiedLoc = new ResourceLocation(str[1], str[2]);

if (jsonCache.containsKey(nonProxiedLoc)) {
element = jsonCache.get(nonProxiedLoc);
} else {
InputStream nonProxied = Minecraft.getMinecraft().getResourceManager().getResource(
nonProxiedLoc
).getInputStream();
Reader reader = new InputStreamReader(nonProxied);

try {
element = JsonUtils.fromJson(UnlimitedChiselWorks.GSON, reader, JsonElement.class);
} catch (Exception e) {
element = null;
reader.close();
nonProxied.close();
}
}

if (element != null) {
JsonElement newElement = parseJsonElement(str, element);
byte[] b = UnlimitedChiselWorks.GSON.toJson(newElement).getBytes(Charsets.UTF_8);
byteArrayOutputStream.write(b);
} else {
InputStream nonProxied = Minecraft.getMinecraft().getResourceManager().getResource(
new ResourceLocation(str[1], str[2])
).getInputStream();

while (nonProxied.available() > 0)
byteArrayOutputStream.write(nonProxied.read());

nonProxied.close();
}

byteArrayOutputStream.close();

byte[] out = byteArrayOutputStream.toByteArray();
data.put(location, out);
return new ByteArrayInputStream(out);
} else {
return new ByteArrayInputStream(data.get(location));
}
}

@Override
public boolean resourceExists(ResourceLocation location) {
String[] str = getStr(location);
if (str == null || str[1].isEmpty()) return false;

try {
IResource resource = Minecraft.getMinecraft().getResourceManager().getResource(
new ResourceLocation(str[1], str[2])
);
return true;
} catch (Exception e) {
return false;
}
}

@Override
public Set<String> getResourceDomains() {
return domains;
}

@Nullable
@Override
public <T extends IMetadataSection> T getPackMetadata(MetadataSerializer metadataSerializer, String metadataSectionName) throws IOException {
return null;
}

@Override
public BufferedImage getPackImage() throws IOException {
return null;
}

@Override
public String getPackName() {
return "UCWFakePack";
}

@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
data.clear();
jsonCache.clear();
}
}

+ 205
- 0
src/main/java/pl/asie/ucw/UCWMagic.java View File

@@ -0,0 +1,205 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModel;

import java.awt.*;

public final class UCWMagic {
private UCWMagic() {

}

public static ResourceLocation getLocation(IBlockState state, ModelResourceLocation location, IModel model) {
String domain = location.getResourceDomain();

if ("forestry".equals(domain)) {
String[] name = state.getBlock().getRegistryName().getResourcePath().split("\\.", 2);
IProperty variantProp = state.getBlock().getBlockState().getProperty("variant");
if (variantProp != null) {
String variant = variantProp.getName(state.getValue(variantProp));
if (name.length == 2 && ("planks".equals(name[0]))) {
return new ResourceLocation("forestry", "blocks/wood/" + name[0] + "." + variant);
}
}
} else if ("extratrees".equals(domain)) {
String[] name = state.getBlock().getRegistryName().getResourcePath().split("\\.", 2);
IProperty variantProp = state.getBlock().getBlockState().getProperty("variant");
if (variantProp != null) {
String variant = variantProp.getName(state.getValue(variantProp));
if (name.length == 2 && ("planks".equals(name[0]))) {
return new ResourceLocation("extratrees", "blocks/planks/" + variant);
}
}
}

System.out.println(state);
return model.getTextures().iterator().next();
}

public static ItemStack copyChangeItem(ItemStack stack, Item item) {
return copyChangeItem(stack, item, stack.getItemDamage());
}

public static ItemStack copyChangeItem(ItemStack stack, Item item, int damage) {
ItemStack stackCopy = new ItemStack(item, stack.getCount(), damage);
if (stack.hasTagCompound()) {
stackCopy.setTagCompound(stack.getTagCompound().copy());
}
return stackCopy;
}

private static float hsl_hue2rgb(float v1, float v2, float hue) {
if (hue < 0.0f) hue += 1.0f;
else if (hue > 1.0f) hue -= 1.0f;

if ((6 * hue) < 1) return (v1 + (v2 - v1) * 6.0f * hue);
else if ((2 * hue) < 1) return v2;
else if ((3 * hue) < 2) return (v1 + (v2 - v1) * ((2.0f/3.0f)-hue)*6.0f);
else return v1;
}

private static int asFF(float f) {
return (Math.round(f * 255.0f) & 0xFF);
}

private static int fromHSL(float[] hsl) {
if (hsl[1] == 0) {
return 0xFF000000 | (asFF(hsl[2]) * 0x10101);
} else {
float v2 = hsl[2] < 0.5 ? hsl[2] * (1 + hsl[1]) : (hsl[2] + hsl[1]) - (hsl[1] * hsl[2]);
float v1 = 2 * hsl[2] - v2;

int r = asFF(hsl_hue2rgb(v1, v2, hsl[0] + 1.0f/3.0f));
int g = asFF(hsl_hue2rgb(v1, v2, hsl[0]));
int b = asFF(hsl_hue2rgb(v1, v2, hsl[0] - 1.0f/3.0f));
return 0xFF000000 | (r << 16) | (g << 8) | b;
}
}

private static int fromHSB(float[] hsb) {
return Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
}

private static float[] toHSL(int rgb) {
float r = (float) ((rgb >> 16) & 0xFF) / 255.0f;
float g = (float) ((rgb >> 8) & 0xFF) / 255.0f;
float b = (float) (rgb & 0xFF) / 255.0f;

float cMin = Math.min(Math.min(r, g), b);
float cMax = Math.max(Math.max(r, g), b);
float cDelta = cMax - cMin;

float l = (cMax + cMin) / 2.0f;

if (cMin == cMax) {
return new float[] {0.0f, 0.0f, l};
} else {
float[] hsb = new float[] {
0,
l < 0.5f ? (cDelta / (cMin + cMax)) : (cDelta / (2 - cMax - cMin)),
l
};

float dr = (((cMax - r) / 6.0f) + (cMax / 2.0f)) / cDelta;
float dg = (((cMax - g) / 6.0f) + (cMax / 2.0f)) / cDelta;
float db = (((cMax - b) / 6.0f) + (cMax / 2.0f)) / cDelta;

if (cMax == r) hsb[0] = db - dg;
else if (cMax == g) hsb[0] = (1.0f/3.0f) + dr - db;
else if (cMax == b) hsb[0] = (2.0f/3.0f) + dg - dr;

if (hsb[0] < 0.0f) hsb[0] += 1.0f;
else if (hsb[0] > 1.0f) hsb[0] -= 1.0f;

return hsb;
}
}

private static float[] toHSB(int rgb) {
float[] hsb = new float[3];
Color.RGBtoHSB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, hsb);
return hsb;
}

private static float[] calculateContrast(int[] data) {
float[] contrast = new float[] { Float.MAX_VALUE, Float.MIN_VALUE };

for (int i : data) {
float[] d = toHSB(i);
if (contrast[0] > d[2]) contrast[0] = d[2];
if (contrast[1] < d[2]) contrast[1] = d[2];
}

contrast[1] -= contrast[0];
return contrast;
}

public static int[] transform(TextureAtlasSprite sprite, int frame, TextureAtlasSprite from, TextureAtlasSprite basedUpon) {
int[] texture = sprite.getFrameTextureData(frame)[0];
int width = sprite.getIconWidth();
int height = sprite.getIconHeight();
float[] contrastFrom = calculateContrast(from.getFrameTextureData(0)[0]);
float[] contrastBasedUpon = calculateContrast(basedUpon.getFrameTextureData(0)[0]);
double avgHueFromS = 0;
double avgHueFromC = 0;
double avgHueFrom;
double avgSatFrom = 0;
for (int i : from.getFrameTextureData(0)[0]) {
float[] hd = toHSB(i);
avgHueFromS += Math.sin(hd[0] * 2 * Math.PI);
avgHueFromC += Math.cos(hd[0] * 2 * Math.PI);
avgSatFrom += hd[1];
}
avgHueFrom = Math.atan2(avgHueFromS, avgHueFromC) / 2.0f / Math.PI;
avgSatFrom /= from.getIconWidth() * from.getIconHeight();

int[] texData = new int[texture.length];
for (int iy = 0; iy < height; iy++) {
for (int ix = 0; ix < width; ix++) {
int i = iy*width+ix;
int it = texture[i];
int ibu = from.getFrameTextureData(0)[0][(iy % from.getIconHeight())*from.getIconWidth() + (ix % from.getIconWidth())];

float[] hsbTex = toHSB(it);
float[] hsbBu = toHSB(ibu);
if (hsbBu[2] < 0.1 && hsbBu[1] < 0.1 && avgSatFrom >= 0.3) {
hsbBu[0] = (float) avgHueFrom;
hsbBu[1] = (float) avgSatFrom;
}
double normV = (double) (hsbTex[2] - contrastBasedUpon[0]) / contrastBasedUpon[1];
float v = (float) ((normV * contrastFrom[1]) + contrastFrom[0]);

if (v < 0) v = 0;
if (v > 1) v = 1;
texData[i] = fromHSB(new float[]{hsbBu[0], hsbBu[1], v});
}
}
return texData;
}
}

+ 337
- 0
src/main/java/pl/asie/ucw/UCWObjectFactory.java View File

@@ -0,0 +1,337 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraft.world.WorldType;
import net.minecraft.world.biome.Biome;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Random;

public class UCWObjectFactory {
private static final Random proxyRand = new Random();

protected final Block block;
protected final Item item;
protected final IBlockState base;
private final UCWBlockRule rule;

public UCWObjectFactory(UCWBlockRule rule, IBlockState base, ResourceLocation location) {
this.rule = rule;
this.base = base;

this.block = new BlockUCW();
this.item = new ItemUCW(block);

this.block.setRegistryName(location);
this.item.setRegistryName(location);
}

public static class UCWBlockAccess implements IBlockAccess {
private final IBlockAccess parent;

public UCWBlockAccess(IBlockAccess parent) {
this.parent = parent;
}

@Nullable
@Override
public TileEntity getTileEntity(BlockPos pos) {
return parent.getTileEntity(pos);
}

@Override
public int getCombinedLight(BlockPos pos, int lightValue) {
return parent.getCombinedLight(pos, lightValue);
}

@Override
public IBlockState getBlockState(BlockPos pos) {
IBlockState state = parent.getBlockState(pos);
if (state.getBlock() instanceof BlockUCW) {
return ((BlockUCW) state.getBlock()).getBaseState();
} else {
return state;
}
}

@Override
public boolean isAirBlock(BlockPos pos) {
return parent.isAirBlock(pos);
}

@Override
public Biome getBiome(BlockPos pos) {
return parent.getBiome(pos);
}

@Override
public int getStrongPower(BlockPos pos, EnumFacing direction) {
return parent.getStrongPower(pos, direction);
}

@Override
public WorldType getWorldType() {
return parent.getWorldType();
}

@Override
public boolean isSideSolid(BlockPos pos, EnumFacing side, boolean _default) {
return parent.isSideSolid(pos, side, _default);
}
}

public class ItemUCW extends ItemBlock {
public ItemUCW(Block block) {
super(block);
setHasSubtypes(true);
}

@Override
@SideOnly(Side.CLIENT)
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, ITooltipFlag flagIn) {
getItemThrough().addInformation(
UCWMagic.copyChangeItem(stack, getItemThrough()),
worldIn, tooltip, flagIn
);
}

@Override
public String getUnlocalizedName() {
return getItemFrom().getUnlocalizedName();
}

@Override
public String getUnlocalizedName(ItemStack stack) {
try {
return getItemFrom().getUnlocalizedName(new ItemStack(base.getBlock().getItemDropped(base, proxyRand, 0), 1, base.getBlock().damageDropped(base)));
} catch (Exception e) {
e.printStackTrace();
return getUnlocalizedName();
}
}
@Override
public String getItemStackDisplayName(ItemStack stack) {
try {
return getItemFrom().getItemStackDisplayName(new ItemStack(base.getBlock().getItemDropped(base, proxyRand, 0), 1, base.getBlock().damageDropped(base)));
} catch (Exception e) {
e.printStackTrace();
return getUnlocalizedName();
}
}

private Item getItemFrom() {
return Item.getItemFromBlock(rule.fromBlock);
}

private Item getItemThrough() {
return Item.getItemFromBlock(rule.throughBlock);
}

@Override
public int getMetadata(int damage) {
if (rule.objectFactories.get(damage) != null) {
return damage;
} else {
return 0;
}
}

@Override
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items) {
Item fromItem = getItemThrough();
NonNullList<ItemStack> proxyList = NonNullList.create();
fromItem.getSubItems(tab, proxyList);
for (ItemStack stack : proxyList) {
if (stack.getItem() == fromItem) {
items.add(UCWMagic.copyChangeItem(stack, this));
}
}
}
}

public class BlockUCW extends Block {
public BlockUCW() {
super(base.getMaterial());
setCreativeTab(base.getBlock().getCreativeTabToDisplayOn());
setUnlocalizedName(base.getBlock().getUnlocalizedName());
}

private IBlockState applyProperties(Block block, IBlockState state) {
IBlockState toState = block.getDefaultState();
for (IProperty property : state.getPropertyKeys()) {
toState = toState.withProperty(property, state.getValue(property));
}
return toState;
}

@Override
public boolean isOpaqueCube(IBlockState state) {
return applyProperties(rule.throughBlock, state).isOpaqueCube();
}

@Override
public boolean isFullCube(IBlockState state) {
return applyProperties(rule.throughBlock, state).isFullCube();
}

@Override
public boolean isFullBlock(IBlockState state) {
return applyProperties(rule.throughBlock, state).isFullBlock();
}

@Override
public boolean isNormalCube(IBlockState state) {
return applyProperties(rule.throughBlock, state).isNormalCube();
}

@Override
public int getLightOpacity(IBlockState state, IBlockAccess world, BlockPos pos) {
return applyProperties(rule.throughBlock, state).getLightOpacity(world, pos);
}

@Override
public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos) {
return applyProperties(rule.throughBlock, state).getLightValue(world, pos);
}

@Override
@SideOnly(Side.CLIENT)
public boolean canRenderInLayer(IBlockState state, BlockRenderLayer layer) {
IBlockState newState = applyProperties(rule.throughBlock, state);
return newState.getBlock().canRenderInLayer(newState, layer);
}

@Override
@SideOnly(Side.CLIENT)
public BlockRenderLayer getBlockLayer() {
return rule.throughBlock.getBlockLayer();
}

@Override
public boolean canHarvestBlock(IBlockAccess world, BlockPos pos, EntityPlayer player) {
return rule.fromBlock.canHarvestBlock(new UCWBlockAccess(world), pos, player);
}

@Override
public float getBlockHardness(IBlockState blockState, World worldIn, BlockPos pos) {
try {
return rule.fromBlock.getBlockHardness(base, worldIn, pos);
} catch (Exception e) {
try {
return rule.throughBlock.getBlockHardness(applyProperties(rule.throughBlock, blockState), worldIn, pos);
} catch (Exception ee) {
return blockHardness;
}
}
}

@Override
public int getFlammability(IBlockAccess world, BlockPos pos, EnumFacing face) {
return rule.fromBlock.getFlammability(new UCWBlockAccess(world), pos, face);
}

@Override
public boolean isFlammable(IBlockAccess world, BlockPos pos, EnumFacing face) {
return rule.fromBlock.isFlammable(new UCWBlockAccess(world), pos, face);
}

@Override
public int getFireSpreadSpeed(IBlockAccess world, BlockPos pos, EnumFacing face) {
return rule.fromBlock.getFireSpreadSpeed(new UCWBlockAccess(world), pos, face);
}

@Override
public boolean isBeaconBase(IBlockAccess worldObj, BlockPos pos, BlockPos beacon) {
return rule.fromBlock.isBeaconBase(new UCWBlockAccess(worldObj), pos, beacon);
}

@Override
public int getHarvestLevel(IBlockState state) {
return base.getBlock().getHarvestLevel(base);
}

@Override
public boolean isToolEffective(String type, IBlockState state) {
return base.getBlock().isToolEffective(type, base);
}

@Override
public int damageDropped(IBlockState state) {
return getMetaFromState(state);
}

@Override
public IBlockState getStateFromMeta(int meta) {
return applyProperties(this, rule.throughBlock.getStateFromMeta(meta));
}

@Override
public int getMetaFromState(IBlockState state) {
return rule.throughBlock.getMetaFromState(applyProperties(rule.throughBlock, state));
}

@Override
public void getSubBlocks(CreativeTabs tab, NonNullList<ItemStack> items) {
item.getSubItems(tab, items);
}

@Override
protected BlockStateContainer createBlockState() {
Collection<IProperty<?>> propertyCollection = rule.throughBlock.getBlockState().getProperties();
IProperty[] properties = propertyCollection.toArray(new IProperty[propertyCollection.size()]);
if (rule.throughBlock.getBlockState() instanceof ExtendedBlockState) {
Collection<IUnlistedProperty<?>> unlistedPropertyCollection = ((ExtendedBlockState) rule.throughBlock.getBlockState()).getUnlistedProperties();
IUnlistedProperty[] unlistedProperties = unlistedPropertyCollection.toArray(new IUnlistedProperty[unlistedPropertyCollection.size()]);
return new ExtendedBlockState(this, properties, unlistedProperties);
} else {
return new BlockStateContainer(this, properties);
}
}

public IBlockState getBaseState() {
return base;
}
}
}

+ 213
- 0
src/main/java/pl/asie/ucw/UCWProxyClient.java View File

@@ -0,0 +1,213 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonObject;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockModelShapes;
import net.minecraft.client.renderer.block.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.IReloadableResourceManager;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.ReflectionHelper;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;

public class UCWProxyClient extends UCWProxyCommon {
private JsonObject chiselCache;

@SubscribeEvent
public void onModelRegistry(ModelRegistryEvent event) {
chiselCache = null;
}

@SubscribeEvent
@SuppressWarnings("unchecked")
public void onTextureStitchPre(TextureStitchEvent.Pre event) {
// don't tell lex
ModelLoader loader;
Map<ModelResourceLocation, IModel> secretSauce = null;
BlockModelShapes blockModelShapes = null;
try {
Class c = Class.forName("net.minecraftforge.client.model.ModelLoader$VanillaLoader");
Field f = c.getDeclaredField("INSTANCE");
f.setAccessible(true);
Object o = f.get(null);
f = c.getDeclaredField("loader");
f.setAccessible(true);
loader = (ModelLoader) f.get(o);
f = ModelLoader.class.getDeclaredField("stateModels");
f.setAccessible(true);
secretSauce = (Map<ModelResourceLocation, IModel>) f.get(loader);
f = ReflectionHelper.findField(ModelBakery.class, "blockModelShapes", "field_177610_k");
f.setAccessible(true);
blockModelShapes = (BlockModelShapes) f.get(loader);
} catch (Exception e) {
throw new RuntimeException(e);
}

for (UCWBlockRule rule : UnlimitedChiselWorks.BLOCK_RULES) {
Map<IBlockState, ModelResourceLocation> fromVariants = blockModelShapes.getBlockStateMapper().getVariants(rule.fromBlock);
Map<IBlockState, ModelResourceLocation> throughVariants = blockModelShapes.getBlockStateMapper().getVariants(rule.throughBlock);
Map<IBlockState, ModelResourceLocation> basedUponVariants = blockModelShapes.getBlockStateMapper().getVariants(rule.basedUponBlock);

for (int i = 0; i < rule.from.size(); i++) {
if (rule.from.get(i) != null) {
IBlockState state = rule.from.get(i);
String s2 = rule.fromBlock.getRegistryName().toString().trim().replaceAll("[^A-Za-z0-9]", "_") + "_" + i;

IModel modelFrom = secretSauce.get(fromVariants.get(state));
IBlockState stateBasedUpon = rule.basedUpon.size() == 1 ? rule.basedUpon.get(0) : rule.basedUpon.get(i);
IModel modelBasedUpon = secretSauce.get(basedUponVariants.get(stateBasedUpon));
ResourceLocation textureFrom = UCWMagic.getLocation(state, fromVariants.get(state), modelFrom);
ResourceLocation textureBasedUpon = UCWMagic.getLocation(stateBasedUpon, basedUponVariants.get(stateBasedUpon), modelBasedUpon);

for (int j = 0; j < 16; j++) {
//for (ModelResourceLocation throughLoc : throughVariants.values()) {
IBlockState throughState = null;
try {
throughState = rule.throughBlock.getStateFromMeta(j);
} catch (Exception e) {
continue;
}
ModelResourceLocation throughLoc = throughVariants.get(throughState);
IModel modelThrough = secretSauce.get(throughLoc);
ImmutableMap.Builder<String, String> textureRemapMap = ImmutableMap.builder();
for (ResourceLocation oldLocation : modelThrough.getTextures()) {
ResourceLocation newLocation = new ResourceLocation("ucw_generated",
"blocks/ucw_ucw_" + s2 + "/" + oldLocation.getResourceDomain() + "/" + oldLocation.getResourcePath().substring(7));

textureRemapMap.put(oldLocation.toString(), newLocation.toString());
event.getMap().setTextureEntry(new TextureAtlasSprite(newLocation.toString()) {
@Override
public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) {
return true;
}

@Override
public boolean load(IResourceManager manager, ResourceLocation location, Function<ResourceLocation, TextureAtlasSprite> textureGetter) {
TextureAtlasSprite fromTex = textureGetter.apply(textureFrom);
TextureAtlasSprite basedUponTex = textureGetter.apply(textureBasedUpon);
TextureAtlasSprite locationTex = textureGetter.apply(oldLocation);

setIconWidth(locationTex.getIconWidth());
setIconHeight(locationTex.getIconHeight());

clearFramesTextureData();
for (int i = 0; i < locationTex.getFrameCount(); i++) {
int[][] pixels = new int[Minecraft.getMinecraft().gameSettings.mipmapLevels + 1][];
pixels[0] = UCWMagic.transform(locationTex, i, fromTex, basedUponTex);
framesTextureData.add(pixels);
}

return false;
}

@Override
public java.util.Collection<ResourceLocation> getDependencies() {
return ImmutableList.of(textureFrom, textureBasedUpon, oldLocation);
}
});
}

UCWObjectFactory factory = rule.objectFactories.get(i);
List<String> propertyNames = new ArrayList<>();
for (IProperty property : factory.block.getBlockState().getProperties()) {
propertyNames.add(property.getName());
}
IBlockState targetState = factory.block.getStateFromMeta(j);
Collections.sort(propertyNames);
String variant = "";
for (String s : propertyNames) {
if (variant.length() > 0) variant += ",";
IProperty property = factory.block.getBlockState().getProperty(s);
variant += s + "=" + property.getName(targetState.getValue(property));
}

ModelResourceLocation targetLoc = new ModelResourceLocation(factory.block.getRegistryName(), variant);
ModelLoader.setCustomModelResourceLocation(factory.item, j, targetLoc);

if (throughLoc.getResourceDomain().equals("chisel")) {
// fun!
try {
if (chiselCache == null) {
InputStream stream = Minecraft.getMinecraft().getResourceManager().getResource(
new ResourceLocation("chisel", "blockstates/default.json")
).getInputStream();
InputStreamReader reader = new InputStreamReader(stream);

chiselCache = JsonUtils.fromJson(UnlimitedChiselWorks.GSON, reader, JsonObject.class);

reader.close();
stream.close();
}

JsonObject variants = chiselCache.get("variants").getAsJsonObject();
if (variants.has(throughLoc.getVariant())) {
String modelPath = variants
.get(throughLoc.getVariant()).getAsJsonObject().get("model").getAsString();
modelPath = modelPath.replaceFirst("chisel:", "ucw_generated:ucw_ucw_" + s2 + "/chisel/");
secretSauce.put(targetLoc, ModelLoaderRegistry.getModel(new ModelResourceLocation(modelPath)));
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
secretSauce.put(targetLoc, modelThrough.retexture(textureRemapMap.build()));
}
}
}
}
}
}

@Override
public void preInit() {
try {
Field field = ReflectionHelper.findField(Minecraft.class, "defaultResourcePacks", "field_110449_ao");
((List) field.get(Minecraft.getMinecraft())).add(UCWFakeResourcePack.INSTANCE);

((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(UCWFakeResourcePack.INSTANCE);

// TODO: Can we get rid of this to save a bit of loading time?
// (We can, but it involves loading Minecraft.<init> a bit early.
// Hmm.)
Minecraft.getMinecraft().refreshResources();
} catch (Exception e) {
e.printStackTrace();
}
}
}

+ 26
- 0
src/main/java/pl/asie/ucw/UCWProxyCommon.java View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

public class UCWProxyCommon {
public void preInit() {

}
}

+ 196
- 0
src/main/java/pl/asie/ucw/UnlimitedChiselWorks.java View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2017 Adrian Siekierka
*
* This file is part of Unlimited Chisel Works.
*
* Unlimited Chisel Works 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.
*
* Unlimited Chisel Works 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 Unlimited Chisel Works. If not, see <http://www.gnu.org/licenses/>.
*/

package pl.asie.ucw;

import com.google.common.base.Charsets;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.NonNullList;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.*;

@Mod(modid = UnlimitedChiselWorks.MODID, version = UnlimitedChiselWorks.VERSION)
public class UnlimitedChiselWorks {
public static final String MODID = "unlimitedchiselworks";
public static final String VERSION = "${version}";
public static final Set<UCWBlockRule> BLOCK_RULES = new LinkedHashSet<>();
protected static final Gson GSON = new Gson();
private static Logger LOGGER;

@SidedProxy(clientSide = "pl.asie.ucw.UCWProxyClient", serverSide = "pl.asie.ucw.UCWProxyCommon")
private static UCWProxyCommon proxy;

private void proposeRule(Path p) throws IOException {
if (Files.isDirectory(p)) {
for (Path pp : Files.newDirectoryStream(p)) {
try {
proposeRule(pp);
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
BufferedReader reader = Files.newBufferedReader(p, Charsets.UTF_8);
try {
JsonObject json = JsonUtils.fromJson(GSON, reader, JsonObject.class);
if (json != null) {
if (json.has("blocks")) {
for (JsonElement element : json.get("blocks").getAsJsonArray()) {
if (element.isJsonObject()) {
try {
UCWBlockRule rule = new UCWBlockRule(element.getAsJsonObject());
if (rule.isValid()) {
if (BLOCK_RULES.contains(rule)) {
LOGGER.warn("Duplicate rule found! " + rule);
} else {
BLOCK_RULES.add(rule);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

private void findRules() {
BLOCK_RULES.clear();

for (ModContainer container : Loader.instance().getActiveModList()) {
File file = container.getSource();
try {
if (file.exists()) {
if (file.isDirectory()) {
File f = new File(file, "assets/" + container.getModId() + "/ucwdefs");
if (f.exists() && f.isDirectory()) {
proposeRule(f.toPath());
}
} else {
FileSystem fs = FileSystems.newFileSystem(file.toPath(), null);
proposeRule(fs.getPath("assets/" + container.getModId() + "/ucwdefs"));
}
}
} catch (NoSuchFileException e) {
// no problem with this one
} catch (IOException e) {
e.printStackTrace();
}
}

LOGGER.info("Found " + BLOCK_RULES.size() + " rules.");
}

@EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER = LogManager.getLogger(MODID);
MinecraftForge.EVENT_BUS.register(this);
MinecraftForge.EVENT_BUS.register(proxy);
proxy.preInit();
}

@SubscribeEvent(priority = EventPriority.LOW)
public void registerBlocks(RegistryEvent.Register<Block> event) {
findRules();

for (UCWBlockRule rule : BLOCK_RULES) {
rule.registerBlocks(event.getRegistry());
}
}

@SubscribeEvent(priority = EventPriority.LOW)
public void registerItems(RegistryEvent.Register<Item> event) {
for (UCWBlockRule rule : BLOCK_RULES) {
rule.registerItems(event.getRegistry());
}
}

@EventHandler
public void init(FMLInitializationEvent event) {
for (UCWBlockRule rule : BLOCK_RULES) {
for (int i = 0; i < rule.from.size(); i++) {
IBlockState fromState = rule.from.get(i);
if (fromState == null) continue;

String groupName = rule.fromCount == 1 ? rule.group : rule.group + "_" + i;
UCWCompatUtils.addChiselVariation(groupName, new ItemStack(fromState.getBlock(), 1, fromState.getBlock().damageDropped(fromState)));

UCWObjectFactory factory = rule.objectFactories.get(i);
NonNullList<ItemStack> stacks = NonNullList.create();
factory.item.getSubItems(CreativeTabs.SEARCH, stacks);
for (ItemStack stack : stacks) {
UCWCompatUtils.addChiselVariation(groupName, stack);
}
}
}
}

@EventHandler
public void postInit(FMLInitializationEvent event) {
for (UCWBlockRule rule : BLOCK_RULES) {
ItemStack stack = new ItemStack(rule.fromBlock, 1, OreDictionary.WILDCARD_VALUE);
int[] ids = OreDictionary.getOreIDs(stack);
if (ids.length > 0) {
for (UCWObjectFactory factory : rule.objectFactories.valueCollection()) {
for (int i : ids) {
OreDictionary.registerOre(OreDictionary.getOreName(i), factory.block);
}
}
}
}
}

@EventHandler
public void onServerStarting(FMLServerStartingEvent event) {
event.registerServerCommand(new CommandUCWDebug());
}
}

+ 324
- 0
src/main/resources/assets/unlimitedchiselworks/ucwdefs/abyssalcraft.json View File

@@ -0,0 +1,324 @@
{
"blocks": [
{
"from": {
"state": "abyssalcraft:dreadbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:dreadbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick1",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:dreadbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick2",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:abybrick#type=normal"
},
"through": {
"block": "chisel:stonebrick",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:abybrick#type=normal"
},
"through": {
"block": "chisel:stonebrick1",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:abybrick#type=normal"
},
"through": {
"block": "chisel:stonebrick2",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:darkstone_brick#type=normal"
},
"through": {
"block": "chisel:stonebrick",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:darkstone_brick#type=normal"
},
"through": {
"block": "chisel:stonebrick1",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:darkstone_brick#type=normal"
},
"through": {
"block": "chisel:stonebrick2",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:abydreadbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:abydreadbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick1",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:abydreadbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick2",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:ethaxiumbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:ethaxiumbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick1",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:ethaxiumbrick#type=normal"
},
"through": {
"block": "chisel:stonebrick2",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:cstonebrick#type=normal"
},
"through": {
"block": "chisel:stonebrick",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:cstonebrick#type=normal"
},
"through": {
"block": "chisel:stonebrick1",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"state": "abyssalcraft:cstonebrick#type=normal"
},
"through": {
"block": "chisel:stonebrick2",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"block": "abyssalcraft:dltplank",
"iterate": [
"variant"
]
},
"through": {
"block": "chisel:planks-oak",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:planks#variant=oak"
}
},
{
"from": {
"block": "abyssalcraft:cobblestone",
"iterate": [
"type"
]
},
"through": {
"block": "chisel:cobblestone",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:cobblestone"
}
},
{
"from": {
"block": "abyssalcraft:cobblestone",
"iterate": [
"type"
]
},
"through": {
"block": "chisel:cobblestone1",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:cobblestone"
}
},
{
"from": {
"block": "abyssalcraft:cobblestone",
"iterate": [
"type"
]
},
"through": {
"block": "chisel:cobblestone2",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:cobblestone"
}
}
]
}

+ 74
- 0
src/main/resources/assets/unlimitedchiselworks/ucwdefs/ae2.json View File

@@ -0,0 +1,74 @@
{
"blocks": [
{
"from": {
"block": "appliedenergistics2:sky_stone_brick"
},
"through": {
"block": "chisel:stonebrick",
"iterate": [
"variation"
]
},
"based_upon": {
"state": "minecraft:stonebrick#variant=stonebrick"
}
},
{
"from": {
"block": "appliedenergistics2:sky_stone_brick"
},
"through": {
"block": "chisel:stonebrick1",
"iterate": [
"variation"
]
},
"based_upon": {