use of pl.asie.charset.lib.utils.ThreeState in project Charset by CharsetMC.
the class CharsetTweakBlockCarrying method canCarry.
protected static boolean canCarry(World world, BlockPos pos) {
IBlockState state = world.getBlockState(pos);
Block block = state.getBlock();
boolean hasTileEntity = state.getBlock().hasTileEntity(state);
boolean isVanilla = "minecraft".equals(block.getRegistryName().getResourceDomain());
// Set<String> names = new HashSet<>();
Set<ResourceLocation> locs = new HashSet<>();
locs.add(state.getBlock().getRegistryName());
if (hasTileEntity) {
TileEntity tile = world.getTileEntity(pos);
if (tile != null) {
Class<? extends TileEntity> tileClass = tile.getClass();
locs.add(TileEntity.getKey(tileClass));
// names.add(tileClass.getName());
}
}
/* for (ResourceLocation r : locs)
names.add(r.toString()); */
ThreeState allowedIMC = CharsetIMC.INSTANCE.allows("carry", locs);
if (allowedIMC == ThreeState.NO) {
return false;
} else if (allowedIMC == ThreeState.YES) {
return true;
}
// We support all vanilla tile entities.
if (!isVanilla && hasTileEntity)
return false;
// if (block instanceof IPlantable) return false;
if (block instanceof BlockPistonExtension || block instanceof BlockPistonMoving)
return false;
if (block instanceof BlockPistonBase) {
// uses foreign states - do not trust it!
if (!state.getPropertyKeys().contains(BlockPistonBase.EXTENDED) || state.getValue(BlockPistonBase.EXTENDED)) {
return false;
}
}
if (block instanceof IFluidBlock || block instanceof BlockLiquid)
return false;
if (block instanceof BlockPortal || block instanceof BlockEndPortal)
return false;
return true;
}
use of pl.asie.charset.lib.utils.ThreeState in project Charset by CharsetMC.
the class CharsetTweakBonemeal method onApplyBonemeal.
@SubscribeEvent
public void onApplyBonemeal(BonemealEvent event) {
if (event.getWorld().isRemote) {
return;
}
IBlockState state = event.getBlock();
Block block = state.getBlock();
IBlockState stateNew = null;
ThreeState instantGrowth = CharsetIMC.INSTANCE.allows("instantBonemeal", block.getRegistryName());
ThreeState growth = CharsetIMC.INSTANCE.allows("bonemeal", block.getRegistryName());
if (instantGrowth == ThreeState.MAYBE) {
instantGrowth = ThreeState.from(instantGrowthDefault);
}
if (growth == ThreeState.MAYBE) {
growth = growthWhitelist ? ThreeState.NO : ThreeState.YES;
}
if (growth == ThreeState.NO) {
event.setCanceled(true);
return;
} else if (instantGrowth == ThreeState.NO) {
return;
}
if (block instanceof BlockCrops) {
// crops
stateNew = ((BlockCrops) block).withAge(((BlockCrops) block).getMaxAge());
} else if (state.getPropertyKeys().contains(BlockCocoa.AGE)) {
// cocoa
stateNew = withMax(state, BlockCocoa.AGE);
} else if (block instanceof BlockMushroom) {
// mushroom
((BlockMushroom) block).grow(event.getWorld(), event.getWorld().rand, event.getPos(), state);
event.setResult(Event.Result.ALLOW);
return;
} else if (block instanceof BlockSapling) {
// saplings
((BlockSapling) block).generateTree(event.getWorld(), event.getPos(), state, event.getWorld().rand);
event.setResult(Event.Result.ALLOW);
return;
} else if (state.getPropertyKeys().contains(BlockStem.AGE)) {
// stem
stateNew = withMax(state, BlockStem.AGE);
} else if (block instanceof BlockDoublePlant || block instanceof BlockTallGrass) {
// do nothing, they already grow instantly
return;
} else if (block instanceof BlockGrass) {
return;
} else if (block instanceof IGrowable && heuristicEnabled) {
// heuristic
int i = 128;
boolean canGrow = true;
while (i-- > 0 && canGrow) {
IBlockState stateTmp = event.getWorld().getBlockState(event.getPos());
Block blockTmp = stateTmp.getBlock();
if (blockTmp instanceof IGrowable) {
if (((IGrowable) blockTmp).canGrow(event.getWorld(), event.getPos(), event.getBlock(), false)) {
((IGrowable) blockTmp).grow(event.getWorld(), event.getWorld().rand, event.getPos(), event.getBlock());
canGrow = ((IGrowable) blockTmp).canGrow(event.getWorld(), event.getPos(), event.getBlock(), false);
}
}
}
if (canGrow) {
ModCharset.logger.warn("Found block " + block.getRegistryName() + " which insists on continuing to grow! Odd. Perhaps the Charset mod author would like to know more?");
}
event.setResult(Event.Result.ALLOW);
return;
} else {
// no handler
return;
}
if (stateNew != null) {
if (stateNew != state) {
event.getWorld().setBlockState(event.getPos(), stateNew, 2);
event.setResult(Event.Result.ALLOW);
} else {
return;
}
}
}
use of pl.asie.charset.lib.utils.ThreeState in project Charset by CharsetMC.
the class ModuleLoader method readDataTable.
@SuppressWarnings("unchecked")
private void readDataTable(ASMDataTable table) {
Multimap<String, String> unmetDependencies = HashMultimap.create();
Set<String> enabledModules = new HashSet<>();
Set<String> compatModules = new HashSet<>();
Map<String, ASMDataTable.ASMData> moduleData = new HashMap<>();
Property baseProfileProp = ModCharset.configGeneral.get("general", "profile", "DEFAULT");
baseProfileProp.setValidValues(new String[] { "DEFAULT", "STABLE", "TESTING", "EXPERIMENTAL" });
baseProfileProp.setLanguageKey("config.charset.profile.name");
baseProfileProp.setRequiresMcRestart(true);
ModuleProfile profile, defaultProfile;
if (ModCharset.INDEV) {
defaultProfile = ModuleProfile.INDEV;
} else if (ModCharset.defaultOptions.containsKey("profile")) {
defaultProfile = getProfileFromString(ModCharset.defaultOptions.get("profile"));
} else {
defaultProfile = ModuleProfile.STABLE;
}
baseProfileProp.setComment("Set the base profile for Charset.\nThis will give you a default set of modules based on stability.\nAllowed values: DEFAULT, STABLE, TESTING, EXPERIMENTAL (DEFAULT means " + defaultProfile.name() + ")\nFor fine-grained configuration, check modules.cfg!");
if ("DEFAULT".equals(baseProfileProp.getString().toUpperCase())) {
profile = defaultProfile;
} else {
profile = getProfileFromString(baseProfileProp.getString());
}
ModCharset.profile = profile;
ModCharset.logger.info("Charset profile is " + ModCharset.profile);
ConfigCategory category = ModCharset.configModules.getCategory("overrides");
category.setComment("Overrides can have one of three values: DEFAULT, ENABLE, DISABLE\nDEFAULT will enable the module based on your profile settings and dependency availability.");
category = ModCharset.configModules.getCategory("categories");
category.setComment("This section allows you to disable certain categories of content, based on a tag system.");
boolean configDirty = false;
Map<String, Boolean> categoryMap = new HashMap<>();
// Initialize categories
for (ASMDataTable.ASMData data : table.getAll(CharsetModule.class.getName())) {
Map<String, Object> info = data.getAnnotationInfo();
List<String> tags = (List<String>) info.getOrDefault("categories", Collections.emptyList());
for (String s : tags) {
if (!categoryMap.containsKey(s)) {
Property prop = ModCharset.configModules.get("categories", s, !CATEGORIES_OFF_BY_DEFAULT.contains(s));
prop.setRequiresMcRestart(true);
categoryMap.put(s, prop.getBoolean());
}
}
}
for (ASMDataTable.ASMData data : table.getAll(CharsetModule.class.getName())) {
Map<String, Object> info = data.getAnnotationInfo();
String name = (String) info.get("name");
String desc = (String) info.get("description");
if (desc == null)
desc = "";
ModuleProfile modProfile = ModuleProfile.valueOf(((ModAnnotation.EnumHolder) info.get("profile")).getValue());
Boolean isDefault = (Boolean) info.getOrDefault("isDefault", true);
Boolean compat = modProfile == ModuleProfile.COMPAT;
Boolean clientOnly = (Boolean) info.getOrDefault("isClientOnly", false);
Boolean serverOnly = (Boolean) info.getOrDefault("isServerOnly", false);
List<String> tags = (List<String>) info.getOrDefault("categories", Collections.emptyList());
String moduleGuiClass = (String) info.getOrDefault("moduleConfigGui", "");
if (moduleGuiClass.length() > 0) {
moduleGuiClasses.put(name, moduleGuiClass);
}
moduleData.put(name, data);
ThreeState override = ThreeState.MAYBE;
if ((Boolean) info.getOrDefault("isVisible", true)) {
if (modProfile == ModuleProfile.INDEV && profile != ModuleProfile.INDEV) {
override = ThreeState.NO;
} else {
if (compat) {
Property prop = ModCharset.configModules.get("compat", name, isDefault);
prop.setRequiresMcRestart(true);
if (!prop.getBoolean())
override = ThreeState.NO;
} else {
Property prop = ModCharset.configModules.get("overrides", name, "DEFAULT");
prop.setValidValues(new String[] { "DEFAULT", "ENABLE", "DISABLE" });
prop.setRequiresMcRestart(true);
if (desc.length() > 0)
desc += " ";
desc += "[Profile: " + modProfile.name().toUpperCase() + "";
if (!isDefault) {
desc += ", off by default!";
}
desc += "]";
if (!desc.equals(prop.getComment())) {
prop.setComment(desc);
configDirty = true;
}
if (prop.getString().toUpperCase().startsWith("ENABLE")) {
override = ThreeState.YES;
} else if (prop.getString().toUpperCase().startsWith("DISABLE")) {
override = ThreeState.NO;
} else if (!"DEFAULT".equals(prop.getString().toUpperCase())) {
ModCharset.logger.warn("Invalid value for '" + name + "' override: '" + prop.getString() + ";");
}
}
}
}
if (clientOnly && !FMLCommonHandler.instance().getSide().isClient()) {
continue;
}
if (serverOnly && !FMLCommonHandler.instance().getSide().isServer()) {
continue;
}
if (compat) {
compatModules.add(name);
}
if (override == ThreeState.MAYBE && isDefault) {
List<String> antideps = (List<String>) info.get("antidependencies");
if (antideps != null) {
for (String dep : antideps) {
if (isDepPresent(dep, enabledModules)) {
ModCharset.logger.info("Antidependency " + dep + " is present - disabling otherwise not forced module " + name + ".");
isDefault = false;
break;
}
}
}
for (String s : tags) {
if (!categoryMap.get(s)) {
ModCharset.logger.info("Category " + s + " is disabled - disabling otherwise not forced module " + name + ".");
isDefault = false;
}
}
}
if (!compat && modProfile != ModuleProfile.FORCED && modProfile.ordinal() > profile.ordinal()) {
isDefault = false;
}
EnableInformation enableInfo = new EnableInformation(isDefault, override);
if (enableInfo.isEnabled()) {
enabledModules.add(name);
enableInfoMap.put(name, enableInfo);
if (!"lib".equals(name))
dependencies.put(name, "lib");
List<String> deps = (List<String>) info.get("dependencies");
if (deps != null) {
dependencies.putAll(name, deps);
}
}
}
if (ModCharset.configGeneral.hasChanged()) {
ModCharset.configGeneral.save();
}
if (ModCharset.configModules.hasChanged() || configDirty) {
ModCharset.configModules.save();
configDirty = false;
}
int removedCount = 1;
while (removedCount > 0) {
removedCount = 0;
for (String name : enabledModules) {
if (dependencies.containsKey(name)) {
for (String dep : dependencies.get(name)) {
boolean optional = false;
if (dep.startsWith("optional:")) {
optional = true;
dep = dep.substring("optional:".length());
}
boolean met = optional || isDepPresent(dep, enabledModules);
if (!met) {
enableInfoMap.get(name).dependenciesMet = false;
unmetDependencies.put(name, dep);
break;
}
}
}
}
Iterator<String> unmetDepKey = unmetDependencies.keySet().iterator();
while (unmetDepKey.hasNext()) {
String depMod = unmetDepKey.next();
EnableInformation enableInfo = enableInfoMap.get(depMod);
if (!enableInfo.isEnabled()) {
if (!compatModules.contains(depMod)) {
ModCharset.logger.info("Module " + depMod + " requires " + joinerComma.join(unmetDependencies.get(depMod)) + ", but is not force-enabled. You can ignore this - it is not an error, just information.");
}
removedCount++;
enabledModules.remove(depMod);
unmetDepKey.remove();
}
}
}
for (String name : enabledModules) {
if (ModCharset.INDEV) {
ModCharset.logger.info("Instantiating module " + name);
}
ASMDataTable.ASMData data = moduleData.get(name);
try {
Object o = getClass(data).newInstance();
loadedModules.put(name, o);
loadedModulesByClass.put(data.getClassName(), o);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if (unmetDependencies.size() > 0) {
List<String> depStrings = new ArrayList<>(unmetDependencies.size());
for (String depMod : unmetDependencies.keys()) {
depStrings.add(depMod + "<-[" + joinerComma.join(unmetDependencies.get(depMod)) + "]");
}
throw new RuntimeException("The following mandatory dependencies were not met: " + joinerComma.join(depStrings));
}
iterateModules(table, Mod.EventHandler.class.getName(), (data, instance) -> {
String methodName = data.getObjectName().substring(0, data.getObjectName().indexOf('('));
String methodDesc = data.getObjectName().substring(methodName.length());
MethodType methodType = MethodType.fromMethodDescriptorString(methodDesc, classLoader);
if (ModCharset.INDEV) {
if (methodType.parameterCount() != 1) {
throw new RuntimeException("Invalid parameter count " + methodType.parameterCount() + " for EventHandler in " + instance.getClass() + "!");
}
}
try {
MethodHandle methodHandle = MethodHandles.lookup().findVirtual(getClass(data), methodName, methodType);
List<Pair<String, MethodHandle>> list = loaderHandles.computeIfAbsent(methodType.parameterType(0), k -> new ArrayList<>());
list.sort(Comparator.comparing(Pair::getLeft));
list.add(Pair.of(loadedModules.inverse().get(instance), methodHandle));
} catch (NoSuchMethodException e) {
// method has been annotated away, ignore
} catch (Exception e) {
throw new RuntimeException(e);
}
});
iterateModules(table, CharsetModule.Instance.class.getName(), (data, instance) -> {
try {
String instString = (String) data.getAnnotationInfo().get("value");
if (instString == null || instString.equals("")) {
getField(data).set(instance, instance);
} else {
Object inst2 = loadedModules.get(instString);
getField(data).set(instance, inst2);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
iterateModules(table, CharsetModule.PacketRegistry.class.getName(), (data, instance) -> {
String id = (String) data.getAnnotationInfo().get("value");
if (id == null)
id = loadedModules.inverse().get(instance);
try {
String channelName = "chrs:" + id.substring(id.lastIndexOf('.') + 1);
getField(data).set(instance, new PacketRegistry(channelName));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
iterateModules(table, CharsetModule.Configuration.class.getName(), (data, instance) -> {
String id = (String) data.getAnnotationInfo().get("value");
if (id == null)
id = loadedModules.inverse().get(instance);
try {
Configuration config = new Configuration(ModCharset.getModuleConfigFile(id));
getField(data).set(instance, config);
moduleConfigs.put(id, config);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Side side = FMLCommonHandler.instance().getSide();
for (ASMDataTable.ASMData data : table.getAll(CharsetModule.SidedProxy.class.getName())) {
String clientSide = (String) data.getAnnotationInfo().get("clientSide");
String serverSide = (String) data.getAnnotationInfo().get("serverSide");
try {
Field f = getField(data);
f.set(null, Class.forName(side == Side.CLIENT ? clientSide : serverSide).newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
List<String> sortedModules = new ArrayList<>();
Set<String> remainingModules = Sets.newHashSet(enabledModules);
while (!remainingModules.isEmpty()) {
Iterator<String> remainingIterator = remainingModules.iterator();
boolean added = false;
while (remainingIterator.hasNext()) {
String s = remainingIterator.next();
boolean canAdd = true;
for (String dep : dependencies.get(s)) {
if (!dep.startsWith("mod:") && !dep.startsWith("optional:") && !sortedModules.contains(dep)) {
canAdd = false;
break;
}
}
if (canAdd) {
added = true;
sortedModules.add(s);
remainingIterator.remove();
}
}
if (!added) {
throw new RuntimeException("Cyclic dependency within Charset modules! Report!");
}
}
for (List<Pair<String, MethodHandle>> list : loaderHandles.values()) {
list.sort(Comparator.comparingInt(a -> sortedModules.indexOf(a.getKey())));
}
for (String s : sortedModules) {
MinecraftForge.EVENT_BUS.register(loadedModules.get(s));
}
for (ASMDataTable.ASMData data : table.getAll(CharsetCompatAnnotation.class.getName())) {
String id = (String) data.getAnnotationInfo().get("value");
try {
addClassNames(table, Class.forName(data.getClassName()), id);
} catch (Exception e) {
e.printStackTrace();
}
}
passEvent(new CharsetLoadConfigEvent(true));
if (ModCharset.configModules.hasChanged() || configDirty) {
ModCharset.configModules.save();
configDirty = false;
}
}
use of pl.asie.charset.lib.utils.ThreeState in project Charset by CharsetMC.
the class LockEventHandler method onAttachCapabilities.
@SubscribeEvent
public void onAttachCapabilities(AttachCapabilitiesEvent<TileEntity> event) {
TileEntity tile = event.getObject();
ResourceLocation location = TileEntity.getKey(tile.getClass());
if (// f.e. IC2 energy net internals
location == null)
return;
ThreeState state = CharsetIMC.INSTANCE.allows("lock", location);
boolean hasCap = state == ThreeState.YES;
if (state == ThreeState.MAYBE) {
if (tile instanceof TileEntityLockable) {
hasCap = true;
}
}
if (hasCap) {
if (PROVIDER == null) {
PROVIDER = new CapabilityProviderFactory<>(Capabilities.LOCKABLE, Capabilities.LOCKABLE_STORAGE);
}
event.addCapability(LOCKABLE, PROVIDER.create(new Lockable(tile)));
}
}
use of pl.asie.charset.lib.utils.ThreeState in project Charset by CharsetMC.
the class CharsetTweakBlockCarrying method canCarry.
protected static boolean canCarry(Entity entity) {
Class<? extends Entity> entityClass = entity.getClass();
EntityEntry entry = EntityRegistry.getEntry(entityClass);
if (entry == null) {
ModCharset.logger.warn(entityClass.getName() + " has no EntityEntry!");
} else {
ThreeState allowedIMC = CharsetIMC.INSTANCE.allows("carry", entry.getRegistryName());
if (allowedIMC == ThreeState.NO) {
return false;
} else if (allowedIMC == ThreeState.YES) {
return true;
}
}
return true;
}
Aggregations