Compare commits

...

20 Commits

Author SHA1 Message Date
Sebastian Hartte 5efc085693 Fix tiles that have a "powered" block state from not being able to be broken when
they are connected to a powered grid.
2020-08-24 23:54:37 +02:00
Sebastian Hartte aff94cec8c Fix search box interactions in the interface terminal. 2020-08-24 22:33:04 +02:00
Sebastian Hartte 2184d03d0b Actually save the rotation when a tile is rotated. 2020-08-24 01:06:26 +02:00
Sebastian Hartte 44c0931c02 Fixes #4635: Actually remove requesters when removing requesters. 2020-08-23 20:47:05 +02:00
yueh 423ab81813 Added step to publish to modmaven (#4607)
(cherry picked from commit 7e1bfdb5ac)
2020-08-21 20:40:03 +02:00
shartte 4e42b17e81 Fixes #4590: Crystal seeds (other than certus) don't display their growth stages. (#4618) 2020-08-19 16:43:45 +02:00
shartte fc0f8eab56 Fixes #4611: Use of client-side only method for Tiny TNT explosion. (#4612) 2020-08-18 01:33:47 +02:00
shartte 41b7900706 Fixes #4598: Incorrectly rotated face for determining block lightlevel in ME Chest renderer. (#4599) (#4609)
(cherry picked from commit 954ce1442e)
2020-08-17 21:58:51 +02:00
shartte 7656157b0d Fixes #4602: Prevent encoding invalid patterns and handle corrupted patterns a little more gracefully. (#4608) 2020-08-17 21:49:37 +02:00
Sebastian Hartte 87c2c94bd4 Use minus sign for minus buttons in number widget. 2020-08-11 16:31:20 +02:00
yueh d591a1492c Fixes #4583: Confine fluix crafting into the same block (#4586)
Fluix crystals will now spawn within an area around the center of the block as well as some tuned down motion while still maintaining some randomness.
2020-08-10 11:30:04 +02:00
shartte d1ba26311b One Spatial Dimension (#4570)
* Ported the "one spatial dimension" concept from pre-1.15

* Apply lighting updates after moving chunks.
Mark world data as dirty when changing it.

* Consolidated naming of spatial storage world/dimension.
Use server light manager to update lighting info in chunk.

* Save last transition information,
and add ae2 spatial command to interact with spatial storage.

* Formatting fixes.

* Improved docs for the origin generation.

Inverted condition on when the x/z axis are flipped.
Also added a helper to map a plot to a region file

* Remove TransitionResult since it's only used in lieu of a boolean.
Rework transition to make the checks BEFORE allocating a new cell.

* Removed unused imports.

Co-authored-by: yueh <yueh@users.noreply.github.com>
2020-08-10 11:29:07 +02:00
shartte 8733c2c11f Fix Special Model Registration (#4577)
* Fixes #4575 by updating Forge (ModelRegistryEvent is a modbus event but was misflagged as not being one). And update Forge because their breaking change breaks our mod.

* Update gradle.properties

Co-authored-by: yueh <yueh@users.noreply.github.com>

* Update src/main/resources/META-INF/mods.toml

Co-authored-by: yueh <yueh@users.noreply.github.com>

Co-authored-by: yueh <yueh@users.noreply.github.com>
2020-08-10 11:25:26 +02:00
yueh 4230fc7325 Fixes #4576: Append the amount to each button (#4580) 2020-08-09 13:23:24 +02:00
shartte 484af8baf3 Fixes #4574 by referencing only non-pure fluix crystals in the fluix dust grinder recipe. (#4578) 2020-08-09 12:24:42 +02:00
shartte 9456f639d4 Simplify "unlit" quad loading and move to Mixins (#4569)
* Simplified the UV loader concept: We only need it to make quads "unlit" which means that the lighting system is not applied to them. They always render at their full brightness.

* More documentation and slight cleanups.
2020-08-09 01:27:19 +02:00
shartte fe753c540b Fixes #4571: When not used for displaying localized text, specify Locale.ROOT for toLowerCase/toUpperCase to avoid issues with locale-specific non-ASCII lowercase conversions for ASCII uppercase characters (i.e. turkish lowercase i for uppercase I). (#4573) 2020-08-08 14:56:51 +02:00
Sebastian Hartte 2fabab3a6a Fix AO lighting for faces not fully snapped to block edges. 2020-08-08 02:20:40 +02:00
shartte 6f39bd8fe8 Move the nether quartz dust tag to the forge namespace and use it instead of AE's internal one. (#4568) 2020-08-07 23:13:02 +02:00
yueh c7d3877129 Use the declared power drain for p2p tunnels (#4567) 2020-08-06 20:07:40 +02:00
144 changed files with 1794 additions and 1996 deletions
+9 -1
View File
@@ -55,7 +55,15 @@ jobs:
KEY_STORE_ALIAS: ${{ secrets.KEY_STORE_ALIAS }}
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew publish --no-daemon --max-workers 1
run: ./gradlew publishMavenPublicationToGitHubPackagesRepository --no-daemon --max-workers 1
- name: Publish to modmaven
env:
KEY_STORE_PASS: ${{ secrets.KEY_STORE_PASS }}
KEY_STORE_ALIAS: ${{ secrets.KEY_STORE_ALIAS }}
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
MODMAVEN_USER: ${{ secrets.MODMAVEN_USER }}
MODMAVEN_PASSWORD: ${{ secrets.MODMAVEN_PASSWORD }}
run: ./gradlew publishMavenPublicationToModmavenRepository --no-daemon --max-workers 1
- name: Prepare artifact metadata
id: prepare_artifact_metadata
run: |
+8
View File
@@ -205,5 +205,13 @@ publishing {
name = "GitHubPackages"
url = "https://maven.pkg.github.com/AppliedEnergistics/Applied-Energistics-2"
}
maven {
credentials {
username System.getenv("MODMAVEN_USER")
password System.getenv("MODMAVEN_PASSWORD")
}
name = "modmaven"
url = "https://modmaven.k-4u.nl/artifactory/local-releases/"
}
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ artifact_basename=appliedenergistics2
minecraft_release=1.16
minecraft_version=1.16.1
mcp_mappings=20200723-1.16.1
forge_version=32.0.93
forge_version=32.0.108
#########################################################
# Provided APIs #
@@ -23,6 +23,8 @@
package appeng.api.config;
import java.util.Locale;
/**
* Represent the security systems basic permissions, these are not for
* anti-griefing, they are part of the mod as a gameplay feature.
@@ -58,7 +60,7 @@ public enum SecurityPermissions {
*/
SECURITY;
private final String translationKey = "gui.appliedenergistics2.security." + this.name().toLowerCase();
private final String translationKey = "gui.appliedenergistics2.security." + this.name().toLowerCase(Locale.ROOT);
public String getTranslatedName() {
return this.translationKey + ".name";
@@ -53,6 +53,8 @@ public interface ICraftingHelper {
* @param stack If null, a new item will be created to hold the encoded pattern.
* Otherwise the given item must already contains an encoded
* pattern that will be overwritten.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
* @return A new encoded pattern, or the given stack with the pattern encoded in
* it.
*/
@@ -73,6 +75,8 @@ public interface ICraftingHelper {
* operation by the ME system.
* @param allowSubstitutes Controls whether the ME system will allow the use of
* equivalent items to craft this recipe.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
*/
ItemStack encodeCraftingPattern(@Nullable ItemStack stack, ICraftingRecipe recipe, ItemStack[] in, ItemStack out,
boolean allowSubstitutes);
@@ -1,38 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 AlgorithmX2
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package appeng.api.implementations;
/**
* Defines the result of performing a transition from the world into a storage
* cell, if its possible, and what the energy usage is.
*/
public class TransitionResult {
public final boolean success;
public final double energyUsage;
public TransitionResult(final boolean success, final double power) {
this.success = success;
this.energyUsage = power;
}
}
@@ -25,11 +25,8 @@ package appeng.api.implementations.items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.RegistryKey;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import appeng.api.implementations.TransitionResult;
import appeng.api.util.WorldCoord;
/**
@@ -52,13 +49,13 @@ public interface ISpatialStorageCell {
int getMaxStoredDim(ItemStack is);
/**
* get the currently stored Dimension id.
* get the currently stored spatial storage plot id.
*
* @param is spatial storage cell
*
* @return dimension id or -1
* @return plot id or -1
*/
RegistryKey<World> getStoredDimension(ItemStack is);
int getAllocatedPlotId(ItemStack is);
/**
* Perform a spatial swap with the contents of the cell, and the world.
@@ -69,7 +66,7 @@ public interface ISpatialStorageCell {
* @param max max coord
* @param playerId owner of current grid or -1
*
* @return result of transition
* @return success of transition
*/
TransitionResult doSpatialTransition(ItemStack is, ServerWorld w, WorldCoord min, WorldCoord max, int playerId);
boolean doSpatialTransition(ItemStack is, ServerWorld w, WorldCoord min, WorldCoord max, int playerId);
}
@@ -1,51 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2017, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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.
*
* Applied Energistics 2 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 Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.api.storage;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
public interface ISpatialDimension {
ServerWorld getWorld(RegistryKey<World> cellDim);
@Nullable
RegistryKey<World> createNewCellDimension(BlockPos capacity);
void deleteCellDimension(RegistryKey<World> cellDim);
boolean isCellDimension(RegistryKey<World> cellDim);
BlockPos getCellDimensionOrigin(RegistryKey<World> cellDim);
BlockPos getCellDimensionSize(RegistryKey<World> cellDim);
/**
* Adds a user-facing tooltip that describes this dimension so that a player can
* keep storage cells apart.
*/
void addCellDimensionTooltip(RegistryKey<World> cellDim, List<ITextComponent> lines);
}
@@ -23,10 +23,8 @@ import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemModelsProperties;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
@@ -18,6 +18,8 @@
package appeng.block.networking;
import java.util.Locale;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
@@ -51,7 +53,7 @@ public class WirelessBlock extends AEBaseTileBlock<WirelessTileEntity> {
@Override
public String getString() {
return this.name().toLowerCase();
return this.name().toLowerCase(Locale.ROOT);
}
}
@@ -30,14 +30,10 @@ import net.minecraft.block.DispenserBlock;
import net.minecraft.dispenser.IDispenseItemBehavior;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemModelsProperties;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import appeng.api.features.AEFeature;
import appeng.block.AEBaseBlockItemChargeable;
import appeng.bootstrap.components.IClientSetupComponent;
import appeng.bootstrap.components.IInitComponent;
import appeng.bootstrap.components.IItemRegistrationComponent;
import appeng.core.AEItemGroup;
+3 -1
View File
@@ -1,6 +1,8 @@
package appeng.client;
import java.util.Locale;
import org.lwjgl.glfw.GLFW;
public enum ActionKey {
@@ -13,7 +15,7 @@ public enum ActionKey {
}
public String getTranslationKey() {
return "key." + this.name().toLowerCase() + ".desc";
return "key." + this.name().toLowerCase(Locale.ROOT) + ".desc";
}
public int getDefaultKey() {
@@ -90,7 +90,9 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
this.searchField.setMaxStringLength(25);
this.searchField.setTextColor(0xFFFFFF);
this.searchField.setVisible(true);
this.searchField.setFocused2(true);
this.searchField.setResponder(str -> this.refreshList());
this.addListener(this.searchField);
this.changeFocus(true);
}
@Override
@@ -131,11 +133,8 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
@Override
public boolean mouseClicked(final double xCoord, final double yCoord, final int btn) {
if (this.searchField.mouseClicked(xCoord, yCoord, btn)) {
if (btn == 1 && this.searchField.isMouseOver(xCoord, yCoord)) {
this.searchField.setText("");
this.refreshList();
}
if (btn == 1 && this.searchField.isMouseOver(xCoord, yCoord)) {
this.searchField.setText("");
return true;
}
@@ -173,11 +172,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
if (character == ' ' && this.searchField.getText().isEmpty()) {
return true;
}
if (this.searchField.charTyped(character, key)) {
this.refreshList();
return true;
}
return false;
return super.charTyped(character, key);
}
@Override
@@ -245,7 +240,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
/**
* Rebuilds the list of interfaces.
*
* <p>
* Respects a search term if present (ignores case) and adding only matching
* patterns.
*/
@@ -338,12 +333,11 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
/**
* Tries to retrieve a cache for a with search term as keyword.
*
* <p>
* If this cache should be empty, it will populate it with an earlier cache if
* available or at least the cache for the empty string.
*
* @param searchTerm the corresponding search
*
* @return a Set matching a superset of the search term
*/
private Set<Object> getCacheForSearchTerm(final String searchTerm) {
@@ -1,5 +1,7 @@
package appeng.client.gui.implementations;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.LongConsumer;
@@ -24,7 +26,7 @@ import appeng.core.AEConfig;
public class NumberEntryWidget implements ITickingWidget {
private static final ITextComponent PLUS = new StringTextComponent("+");
private static final ITextComponent MINUS = new StringTextComponent("+");
private static final ITextComponent MINUS = new StringTextComponent("-");
private final AEBaseScreen<?> parent;
@@ -33,14 +35,7 @@ public class NumberEntryWidget implements ITickingWidget {
private final NumberBox level;
private final NumberEntryType type;
private Button plus1;
private Button plus10;
private Button plus100;
private Button plus1000;
private Button minus1;
private Button minus10;
private Button minus100;
private Button minus1000;
private List<Button> buttons;
public NumberEntryWidget(AEBaseScreen<?> parent, int x, int y, int width, int height, NumberEntryType type,
LongConsumer changeListener) {
@@ -63,14 +58,7 @@ public class NumberEntryWidget implements ITickingWidget {
public void setActive(boolean active) {
this.level.setEnabled(active);
this.plus1.active = active;
this.plus10.active = active;
this.plus100.active = active;
this.plus1000.active = active;
this.minus1.active = active;
this.minus10.active = active;
this.minus100.active = active;
this.minus1000.active = active;
this.buttons.forEach(b -> b.active = active);
}
public void setTextFieldBounds(int x, int y, int width) {
@@ -93,18 +81,23 @@ public class NumberEntryWidget implements ITickingWidget {
int left = parent.getGuiLeft() + x;
int top = parent.getGuiTop() + y;
addButton.accept(this.plus1 = new Button(left, top, 22, 20, PLUS /* + a */, btn -> addQty(a)));
addButton.accept(this.plus10 = new Button(left + 28, top, 28, 20, PLUS /* + b */, btn -> addQty(b)));
addButton.accept(this.plus100 = new Button(left + 62, top, 32, 20, PLUS /* + c */, btn -> addQty(c)));
addButton.accept(this.plus1000 = new Button(left + 100, top, 38, 20, PLUS/* + d */, btn -> addQty(d)));
List<Button> buttons = new ArrayList<>(8);
buttons.add(new Button(left, top, 22, 20, makeLabel(PLUS, a), btn -> addQty(a)));
buttons.add(new Button(left + 28, top, 28, 20, makeLabel(PLUS, b), btn -> addQty(b)));
buttons.add(new Button(left + 62, top, 32, 20, makeLabel(PLUS, c), btn -> addQty(c)));
buttons.add(new Button(left + 100, top, 38, 20, makeLabel(PLUS, d), btn -> addQty(d)));
// Placing this here will give a sensible tab order
addChildren.accept(this.level);
addButton.accept(this.minus1 = new Button(left, top + 42, 22, 20, MINUS /* + a */, btn -> addQty(-a)));
addButton.accept(this.minus10 = new Button(left + 28, top + 42, 28, 20, MINUS /* + b */, btn -> addQty(-b)));
addButton.accept(this.minus100 = new Button(left + 62, top + 42, 32, 20, MINUS /* + c */, btn -> addQty(-c)));
addButton.accept(this.minus1000 = new Button(left + 100, top + 42, 38, 20, MINUS /* + d */, btn -> addQty(-d)));
buttons.add(new Button(left, top + 42, 22, 20, makeLabel(MINUS, a), btn -> addQty(-a)));
buttons.add(new Button(left + 28, top + 42, 28, 20, makeLabel(MINUS, b), btn -> addQty(-b)));
buttons.add(new Button(left + 62, top + 42, 32, 20, makeLabel(MINUS, c), btn -> addQty(-c)));
buttons.add(new Button(left + 100, top + 42, 38, 20, makeLabel(MINUS, d), btn -> addQty(-d)));
this.buttons = buttons;
this.buttons.forEach(addButton);
}
private void addQty(final long i) {
@@ -134,4 +127,8 @@ public class NumberEntryWidget implements ITickingWidget {
this.level.tick();
}
private ITextComponent makeLabel(ITextComponent prefix, int amount) {
return prefix.copyRaw().appendString(String.valueOf(amount));
}
}
@@ -18,6 +18,8 @@
package appeng.client.render;
import java.util.Locale;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.util.Direction;
@@ -111,6 +113,6 @@ public enum FacingToRotation implements IStringSerializable {
@Override
public String getString() {
return name().toLowerCase();
return name().toLowerCase(Locale.ROOT);
}
}
@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
import net.minecraft.client.renderer.model.BakedQuad;
@@ -100,7 +101,7 @@ class CableBuilder {
}
return new RenderMaterial(AtlasTexture.LOCATION_BLOCKS_TEXTURE,
new ResourceLocation(AppEng.MOD_ID, textureFolder + color.name().toLowerCase()));
new ResourceLocation(AppEng.MOD_ID, textureFolder + color.name().toLowerCase(Locale.ROOT)));
}
/**
@@ -19,6 +19,7 @@
package appeng.client.render.cablebus;
import java.util.EnumMap;
import java.util.Locale;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
@@ -74,7 +75,7 @@ public enum CableCoreType {
public RenderMaterial getTexture(AEColor color) {
return new RenderMaterial(AtlasTexture.LOCATION_BLOCKS_TEXTURE,
new ResourceLocation(AppEng.MOD_ID, this.textureFolder + "/" + color.name().toLowerCase()));
new ResourceLocation(AppEng.MOD_ID, this.textureFolder + "/" + color.name().toLowerCase(Locale.ROOT)));
}
}
@@ -18,6 +18,8 @@
package appeng.client.render.crafting;
import java.util.Locale;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -48,7 +50,7 @@ public class CraftingCubeModelLoader implements IModelLoader<CraftingCubeModel>
if (typeEl != null) {
String typeName = deserializationContext.deserialize(typeEl, String.class);
if (typeName != null) {
unitType = AbstractCraftingUnitBlock.CraftingUnitType.valueOf(typeName.toUpperCase());
unitType = AbstractCraftingUnitBlock.CraftingUnitType.valueOf(typeName.toUpperCase(Locale.ROOT));
}
}
if (unitType == null) {
@@ -49,7 +49,7 @@ public class EnergyParticleData implements IParticleData {
reader.expect(' ');
boolean forItem = reader.readBoolean();
reader.expect(' ');
AEPartLocation direction = AEPartLocation.valueOf(reader.readString().toUpperCase());
AEPartLocation direction = AEPartLocation.valueOf(reader.readString().toUpperCase(Locale.ROOT));
return new EnergyParticleData(forItem, direction);
}
@@ -74,7 +74,8 @@ public class EnergyParticleData implements IParticleData {
@Override
public String getParameters() {
return String.format(Locale.ROOT, "%s %s", forItem ? "true" : "false", direction.name().toLowerCase());
return String.format(Locale.ROOT, "%s %s", forItem ? "true" : "false",
direction.name().toLowerCase(Locale.ROOT));
}
}
@@ -34,8 +34,6 @@ import com.google.common.collect.ImmutableList;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
@@ -193,7 +191,7 @@ public class AutoRotatingBakedModel extends DelegateBakedModel {
vec.setX(vec.getX() + 0.5f);
vec.setY(vec.getY() + 0.5f);
vec.setZ(vec.getZ() + 0.5f);
return new float[] { vec.getX(), vec.getY(), vec.getZ() };
return new float[] { snap(vec.getX()), snap(vec.getY()), snap(vec.getZ()) };
case 4:
Vector4f vecc = new Vector4f(fs[0], fs[1], fs[2], fs[3]);
vecc.setX(vecc.getX() - 0.5f);
@@ -203,13 +201,32 @@ public class AutoRotatingBakedModel extends DelegateBakedModel {
vecc.setX(vecc.getX() + 0.5f);
vecc.setY(vecc.getY() + 0.5f);
vecc.setZ(vecc.getZ() + 0.5f);
return new float[] { vecc.getX(), vecc.getY(), vecc.getZ(), vecc.getW() };
return new float[] { snap(vecc.getX()), snap(vecc.getY()), snap(vecc.getZ()), snap(vecc.getW()) };
default:
return fs;
}
}
/**
* This is the same value used by Vanilla's AO lighter.
*/
private static final float EPS = 0.0001f;
/**
* This tries to snap the coordinate to the edges of the block frame, because
* Vanilla uses direct equals comparisons to 0 and 1 for checking if a face
* extends fully towards the edge. This is used primarily for AO calculations.
*/
private static float snap(float x) {
if (Math.abs(x) <= EPS) {
return 0f;
} else if (Math.abs(x - 1) <= EPS) {
return 1f;
}
return x;
}
private float[] transformNormal(float[] fs) {
if (this.face == null) {
switch (fs.length) {
@@ -220,7 +237,7 @@ public class AutoRotatingBakedModel extends DelegateBakedModel {
case 4:
Vector4f vec4 = new Vector4f(fs[0], fs[1], fs[2], fs[3]);
vec4.transform(this.f2r.getMat());
return new float[] { vec4.getX(), vec4.getY(), vec4.getZ(), 0 };
return new float[] { snap(vec4.getX()), snap(vec4.getY()), snap(vec4.getZ()), 0 };
default:
return fs;
@@ -1,210 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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.
*
* Applied Energistics 2 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 Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.render.model;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.blaze3d.matrix.MatrixStack;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.BlockFaceUV;
import net.minecraft.client.renderer.model.BlockModel;
import net.minecraft.client.renderer.model.BlockPart;
import net.minecraft.client.renderer.model.BlockPartFace;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.IModelTransform;
import net.minecraft.client.renderer.model.IUnbakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.model.ItemOverride;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.model.ItemTransformVec3f;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.client.renderer.model.RenderMaterial;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.Direction;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.TransformationMatrix;
import net.minecraftforge.client.model.IModelBuilder;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.IModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
import net.minecraftforge.client.model.pipeline.VertexLighterFlat;
import net.minecraftforge.common.model.TransformationHelper;
public class UVLModelLoader implements IModelLoader<UVLModelLoader.UVLModelWrapper> {
public static final UVLModelLoader INSTANCE = new UVLModelLoader();
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
}
@Override
public UVLModelWrapper read(JsonDeserializationContext deserializationContext, JsonObject modelContents) {
modelContents.remove("loader");
BlockModel blockModel = UVLSERIALIZER.fromJson(modelContents, BlockModel.class);
return new UVLModelWrapper(blockModel);
}
final Gson UVLSERIALIZER = (new GsonBuilder())
.registerTypeAdapter(BlockModel.class, new ModelLoaderRegistry.ExpandedBlockModelDeserializer())
.registerTypeAdapter(BlockPart.class, new BlockPart.Deserializer())
.registerTypeAdapter(BlockPartFace.class, new BlockPartFaceOverrideSerializer())
.registerTypeAdapter(BlockFaceUV.class, new BlockFaceUV.Deserializer())
.registerTypeAdapter(ItemTransformVec3f.class, new ItemTransformVec3f.Deserializer())
.registerTypeAdapter(ItemCameraTransforms.class, new ItemCameraTransforms.Deserializer())
.registerTypeAdapter(ItemOverride.class, new ItemOverride.Deserializer())
.registerTypeAdapter(TransformationMatrix.class, new TransformationHelper.Deserializer()).create();
private static class BlockPartFaceOverrideSerializer extends BlockPartFace.Deserializer {
@Override
public BlockPartFace deserialize(JsonElement p_deserialize_1_, Type p_deserialize_2_,
JsonDeserializationContext p_deserialize_3_) throws JsonParseException {
BlockPartFace blockFace = super.deserialize(p_deserialize_1_, p_deserialize_2_, p_deserialize_3_);
Pair<Float, Float> uvl = this.parseUVL(p_deserialize_1_.getAsJsonObject());
if (uvl != null) {
return new BlockPartFaceWithUVL(blockFace.cullFace, blockFace.tintIndex, blockFace.texture,
blockFace.blockFaceUV, uvl.getLeft(), uvl.getRight());
}
return blockFace;
}
protected Pair<Float, Float> parseUVL(JsonObject object) {
if (!object.has("uvlightmap")) {
return null;
}
object = object.get("uvlightmap").getAsJsonObject();
return new ImmutablePair<>(JSONUtils.getFloat(object, "sky", 0), JSONUtils.getFloat(object, "block", 0));
}
}
private static class BlockPartFaceWithUVL extends BlockPartFace {
private final float sky;
private final float block;
public BlockPartFaceWithUVL(@Nullable Direction cullFaceIn, int tintIndexIn, String textureIn,
BlockFaceUV blockFaceUVIn, float sky, float block) {
super(cullFaceIn, tintIndexIn, textureIn, blockFaceUVIn);
this.sky = sky;
this.block = block;
}
public float getSky() {
return sky;
}
public float getBlock() {
return block;
}
}
public static class UVLModelWrapper implements IModelGeometry<UVLModelWrapper> {
private final BlockModel parent;
public UVLModelWrapper(BlockModel parent) {
this.parent = parent;
}
@Override
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery,
Function<RenderMaterial, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform,
ItemOverrideList overrides, ResourceLocation modelLocation) {
TextureAtlasSprite particle = spriteGetter.apply(owner.resolveTexture("particle"));
IModelBuilder<?> builder = IModelBuilder.of(owner, overrides, particle);
for (BlockPart blockpart : parent.getElements()) {
for (Direction direction : blockpart.mapFaces.keySet()) {
BlockPartFace blockpartface = blockpart.mapFaces.get(direction);
TextureAtlasSprite textureatlassprite1 = spriteGetter
.apply(owner.resolveTexture(blockpartface.texture));
BakedQuad quad = BlockModel.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, direction,
modelTransform, modelLocation);
if (blockpartface instanceof BlockPartFaceWithUVL) {
BlockPartFaceWithUVL uvlFace = (BlockPartFaceWithUVL) blockpartface;
quad = applyPreBakedLighting(quad, textureatlassprite1, uvlFace.sky, uvlFace.block);
}
if (blockpartface.cullFace == null) {
builder.addGeneralQuad(quad);
} else {
builder.addFaceQuad(modelTransform.getRotation().rotateTransform(blockpartface.cullFace), quad);
}
}
}
return builder.build();
}
private BakedQuad applyPreBakedLighting(BakedQuad quad, TextureAtlasSprite sprite, float sky, float block) {
// FIXME: just piping through the quads and manipulating uv index 2 directly
// seems way easier than this
BakedQuadBuilder builder = new BakedQuadBuilder(sprite);
VertexLighterFlat trans = new VertexLighterFlat(Minecraft.getInstance().getBlockColors()) {
@Override
protected void updateLightmap(float[] normal, float[] lightmap, float x, float y, float z) {
lightmap[0] = block;
lightmap[1] = sky;
}
@Override
public void setQuadTint(int tint) {
// Tint requires a block state which we don't have at this point
}
};
MatrixStack identity = new MatrixStack();
trans.setTransform(identity.getLast());
trans.setParent(builder);
quad.pipe(trans);
builder.setQuadTint(quad.getTintIndex());
builder.setQuadOrientation(quad.getFace());
builder.setApplyDiffuseLighting(false);
return builder.build();
}
@Override
public Collection<RenderMaterial> getTextures(IModelConfiguration owner,
Function<ResourceLocation, IUnbakedModel> modelGetter,
Set<com.mojang.datafixers.util.Pair<String, String>> missingTextureErrors) {
return parent.getTextures(modelGetter, missingTextureErrors);
}
}
}
@@ -20,6 +20,7 @@ package appeng.client.render.spatial;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -59,7 +60,7 @@ public class SpatialPylonModel implements BasicUnbakedModel<SpatialPylonModel> {
private static RenderMaterial getTexturePath(SpatialPylonTextureType type) {
return new RenderMaterial(AtlasTexture.LOCATION_BLOCKS_TEXTURE,
new ResourceLocation(AppEng.MOD_ID, "block/spatial_pylon/" + type.name().toLowerCase()));
new ResourceLocation(AppEng.MOD_ID, "block/spatial_pylon/" + type.name().toLowerCase(Locale.ROOT)));
}
}
@@ -142,7 +142,7 @@ public class ChestTileEntityRenderer extends TileEntityRenderer<ChestTileEntity>
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand,
@Nonnull IModelData extraData) {
if (side != null) {
side = r.rotate(side); // This fixes the incorrect lightmap position
side = r.resultingRotate(side); // This fixes the incorrect lightmap position
}
List<BakedQuad> quads = new ArrayList<>(super.getQuads(state, side, rand, extraData));
@@ -261,13 +261,19 @@ public class PatternTermContainer extends MEMonitorableContainer
return new ItemStack[] { out };
}
} else {
boolean hasValue = false;
final ItemStack[] list = new ItemStack[3];
for (int i = 0; i < this.outputSlots.length; i++) {
final ItemStack out = this.outputSlots[i].getStack();
list[i] = out;
if (!out.isEmpty()) {
hasValue = true;
}
}
if (hasValue) {
return list;
}
return list;
}
return null;
-56
View File
@@ -19,7 +19,6 @@
package appeng.core;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
@@ -40,8 +39,6 @@ import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.structure.Structure;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.DistExecutor;
@@ -56,29 +53,10 @@ import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import appeng.block.paint.PaintSplotchesModel;
import appeng.block.qnb.QnbFormedModel;
import appeng.bootstrap.components.IClientSetupComponent;
import appeng.bootstrap.components.IInitComponent;
import appeng.bootstrap.components.IPostInitComponent;
import appeng.capabilities.Capabilities;
import appeng.client.ClientHelper;
import appeng.client.render.DummyFluidItemModel;
import appeng.client.render.FacadeItemModel;
import appeng.client.render.SimpleModelLoader;
import appeng.client.render.cablebus.CableBusModelLoader;
import appeng.client.render.cablebus.P2PTunnelFrequencyModel;
import appeng.client.render.crafting.CraftingCubeModelLoader;
import appeng.client.render.crafting.EncodedPatternModelLoader;
import appeng.client.render.model.BiometricCardModel;
import appeng.client.render.model.ColorApplicatorModel;
import appeng.client.render.model.DriveModel;
import appeng.client.render.model.GlassModel;
import appeng.client.render.model.MemoryCardModel;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.model.UVLModelLoader;
import appeng.client.render.spatial.SpatialPylonModel;
import appeng.core.features.registries.PartModels;
import appeng.core.stats.AdvancementTriggers;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.worlddata.WorldData;
@@ -90,7 +68,6 @@ import appeng.entity.TinyTNTPrimedRenderer;
import appeng.hooks.TickHandler;
import appeng.integration.Integrations;
import appeng.parts.PartPlacement;
import appeng.parts.automation.PlaneModelLoader;
import appeng.server.ServerHelper;
@Mod(AppEng.MOD_ID)
@@ -181,39 +158,6 @@ public final class AppEng {
RenderingRegistry.registerEntityRenderingHandler(ChargedQuartzEntity.TYPE,
m -> new ItemRenderer(m, Minecraft.getInstance().getItemRenderer()));
// TODO: Do not use the internal API
final ApiDefinitions definitions = Api.INSTANCE.definitions();
definitions.getRegistry().getBootstrapComponents(IClientSetupComponent.class)
.forEachRemaining(IClientSetupComponent::setup);
addBuiltInModel("glass", GlassModel::new);
addBuiltInModel("sky_compass", SkyCompassModel::new);
addBuiltInModel("dummy_fluid_item", DummyFluidItemModel::new);
addBuiltInModel("memory_card", MemoryCardModel::new);
addBuiltInModel("biometric_card", BiometricCardModel::new);
addBuiltInModel("drive", DriveModel::new);
addBuiltInModel("color_applicator", ColorApplicatorModel::new);
addBuiltInModel("spatial_pylon", SpatialPylonModel::new);
addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
addBuiltInModel("facade", FacadeItemModel::new);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "encoded_pattern"),
EncodedPatternModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "part_plane"),
PlaneModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "crafting_cube"),
CraftingCubeModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "cable_bus"),
new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
}
@OnlyIn(Dist.CLIENT)
private static <T extends IModelGeometry<T>> void addBuiltInModel(String id, Supplier<T> modelFactory) {
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, id),
new SimpleModelLoader<>(modelFactory));
}
@Nonnull
+65 -8
View File
@@ -18,6 +18,8 @@
package appeng.core;
import java.util.function.Supplier;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@@ -50,7 +52,8 @@ import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.ParticleFactoryRegisterEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import net.minecraftforge.common.extensions.IForgeContainerType;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.IEventBus;
@@ -79,7 +82,10 @@ import appeng.api.networking.security.ISecurityGrid;
import appeng.api.networking.spatial.ISpatialCache;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.networking.ticking.ITickManager;
import appeng.block.paint.PaintSplotchesModel;
import appeng.block.qnb.QnbFormedModel;
import appeng.bootstrap.components.IBlockRegistrationComponent;
import appeng.bootstrap.components.IClientSetupComponent;
import appeng.bootstrap.components.IEntityRegistrationComponent;
import appeng.bootstrap.components.IItemColorRegistrationComponent;
import appeng.bootstrap.components.IItemRegistrationComponent;
@@ -118,6 +124,13 @@ import appeng.client.gui.implementations.UpgradeableScreen;
import appeng.client.gui.implementations.VibrationChamberScreen;
import appeng.client.gui.implementations.WirelessScreen;
import appeng.client.gui.implementations.WirelessTermScreen;
import appeng.client.render.DummyFluidItemModel;
import appeng.client.render.FacadeItemModel;
import appeng.client.render.SimpleModelLoader;
import appeng.client.render.cablebus.CableBusModelLoader;
import appeng.client.render.cablebus.P2PTunnelFrequencyModel;
import appeng.client.render.crafting.CraftingCubeModelLoader;
import appeng.client.render.crafting.EncodedPatternModelLoader;
import appeng.client.render.effects.ChargedOreFX;
import appeng.client.render.effects.CraftingFx;
import appeng.client.render.effects.EnergyFx;
@@ -126,6 +139,13 @@ import appeng.client.render.effects.LightningFX;
import appeng.client.render.effects.MatterCannonFX;
import appeng.client.render.effects.ParticleTypes;
import appeng.client.render.effects.VibrantFX;
import appeng.client.render.model.BiometricCardModel;
import appeng.client.render.model.ColorApplicatorModel;
import appeng.client.render.model.DriveModel;
import appeng.client.render.model.GlassModel;
import appeng.client.render.model.MemoryCardModel;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.spatial.SpatialPylonModel;
import appeng.client.render.tesr.InscriberTESR;
import appeng.client.render.tesr.SkyChestTESR;
import appeng.container.AEBaseContainer;
@@ -194,20 +214,21 @@ import appeng.me.cache.SecurityCache;
import appeng.me.cache.SpatialPylonCache;
import appeng.me.cache.TickManagerCache;
import appeng.mixins.StructureAccessor;
import appeng.parts.automation.PlaneModelLoader;
import appeng.recipes.game.DisassembleRecipe;
import appeng.recipes.game.FacadeRecipe;
import appeng.recipes.handlers.GrinderRecipe;
import appeng.recipes.handlers.GrinderRecipeSerializer;
import appeng.recipes.handlers.InscriberRecipe;
import appeng.recipes.handlers.InscriberRecipeSerializer;
import appeng.server.AECommand;
import appeng.spatial.StorageCellBiome;
import appeng.spatial.StorageChunkGenerator;
import appeng.spatial.SpatialStorageBiome;
import appeng.spatial.SpatialStorageChunkGenerator;
import appeng.spatial.SpatialStorageDimensionIds;
import appeng.tile.AEBaseTileEntity;
import appeng.tile.crafting.MolecularAssemblerRenderer;
import appeng.worldgen.ChargedQuartzOreConfig;
import appeng.worldgen.ChargedQuartzOreFeature;
import appeng.worldgen.meteorite.MeteoriteStructure;
import appeng.worldgen.meteorite.MeteoriteStructurePiece;
final class Registration {
@@ -239,6 +260,39 @@ final class Registration {
@OnlyIn(Dist.CLIENT)
public void modelRegistryEvent(ModelRegistryEvent event) {
registerSpecialModels();
// TODO: Do not use the internal API
final ApiDefinitions definitions = Api.INSTANCE.definitions();
definitions.getRegistry().getBootstrapComponents(IClientSetupComponent.class)
.forEachRemaining(IClientSetupComponent::setup);
addBuiltInModel("glass", GlassModel::new);
addBuiltInModel("sky_compass", SkyCompassModel::new);
addBuiltInModel("dummy_fluid_item", DummyFluidItemModel::new);
addBuiltInModel("memory_card", MemoryCardModel::new);
addBuiltInModel("biometric_card", BiometricCardModel::new);
addBuiltInModel("drive", DriveModel::new);
addBuiltInModel("color_applicator", ColorApplicatorModel::new);
addBuiltInModel("spatial_pylon", SpatialPylonModel::new);
addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
addBuiltInModel("facade", FacadeItemModel::new);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "encoded_pattern"),
EncodedPatternModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "part_plane"),
PlaneModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "crafting_cube"),
CraftingCubeModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "cable_bus"),
new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
}
@OnlyIn(Dist.CLIENT)
private static <T extends IModelGeometry<T>> void addBuiltInModel(String id, Supplier<T> modelFactory) {
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, id),
new SimpleModelLoader<>(modelFactory));
}
/**
@@ -628,6 +682,8 @@ final class Registration {
new ResourceLocation(dimension));
}
MeteoriteStructurePiece.register();
ForgeRegistries.BIOMES.forEach(b -> {
addMeteoriteWorldGen(b);
addQuartzWorldGen(b);
@@ -687,11 +743,12 @@ final class Registration {
MeteoriteStructure.INSTANCE.setRegistryName(MeteoriteStructure.ID),
GenerationStage.Decoration.TOP_LAYER_MODIFICATION);
Registry.register(Registry.CHUNK_GENERATOR_CODEC, AppEng.makeId("storage"), StorageChunkGenerator.CODEC);
Registry.register(Registry.CHUNK_GENERATOR_CODEC, SpatialStorageDimensionIds.CHUNK_GENERATOR_ID,
SpatialStorageChunkGenerator.CODEC);
}
public void registerBiomes(RegistryEvent.Register<Biome> evt) {
evt.getRegistry().register(StorageCellBiome.INSTANCE.setRegistryName(AppEng.makeId("storage")));
evt.getRegistry().register(SpatialStorageBiome.INSTANCE.setRegistryName(SpatialStorageDimensionIds.BIOME_ID));
}
@OnlyIn(Dist.CLIENT)
@@ -726,7 +783,7 @@ final class Registration {
modEventBus.addListener(this::registerParticleFactories);
modEventBus.addListener(this::registerTextures);
MinecraftForge.EVENT_BUS.addListener(this::modelRegistryEvent);
modEventBus.addListener(this::modelRegistryEvent);
modEventBus.addListener(this::registerItemColors);
modEventBus.addListener(this::handleModelBake);
}
@@ -115,7 +115,12 @@ public class ApiCrafting implements ICraftingHelper {
// We use the shared itemstack for an identity lookup.
IAEItemStack ais = Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(is);
return new CraftingPatternDetails(ais, world);
try {
return new CraftingPatternDetails(ais, world);
} catch (IllegalStateException e) {
AELog.warn("Could not decode an invalid pattern %s: %s", is, e);
return null;
}
}
private boolean attemptRecovery(EncodedPatternItem patternItem, ItemStack itemStack, World world) {
@@ -56,6 +56,7 @@ import appeng.hooks.BlockToolDispenseItemBehavior;
import appeng.hooks.MatterCannonDispenseItemBehavior;
import appeng.items.materials.MaterialType;
import appeng.items.misc.CrystalSeedItem;
import appeng.items.misc.CrystalSeedRendering;
import appeng.items.misc.EncodedPatternItem;
import appeng.items.misc.PaintBallItem;
import appeng.items.misc.PaintBallItemRendering;
@@ -299,24 +300,15 @@ public final class ApiItems implements IItems {
this.certusCrystalSeed = registry
.item("certus_crystal_seed",
props -> new CrystalSeedItem(props, materials.purifiedCertusQuartzCrystal().item()))
.bootstrap(item -> new IClientSetupComponent() {
@Override
@OnlyIn(Dist.CLIENT)
public void setup() {
// Expose the growth of the seed to the model system
ItemModelsProperties.func_239418_a_(item, new ResourceLocation("appliedenergistics2:growth"),
(is, w, p) -> CrystalSeedItem.getGrowthTicks(is)
/ (float) CrystalSeedItem.GROWTH_TICKS_REQUIRED);
}
}).features(AEFeature.CRYSTAL_SEEDS).build();
.bootstrap(CrystalSeedRendering::new).features(AEFeature.CRYSTAL_SEEDS).build();
this.fluixCrystalSeed = registry
.item("fluix_crystal_seed",
props -> new CrystalSeedItem(props, materials.purifiedFluixCrystal().item()))
.features(AEFeature.CRYSTAL_SEEDS).build();
.bootstrap(CrystalSeedRendering::new).features(AEFeature.CRYSTAL_SEEDS).build();
this.netherQuartzSeed = registry
.item("nether_quartz_seed",
props -> new CrystalSeedItem(props, materials.purifiedNetherQuartzCrystal().item()))
.features(AEFeature.CRYSTAL_SEEDS).build();
.bootstrap(CrystalSeedRendering::new).features(AEFeature.CRYSTAL_SEEDS).build();
GrowingCrystalEntity.TYPE = registry
.<GrowingCrystalEntity>entity("growing_crystal", GrowingCrystalEntity::new, EntityClassification.MISC)
@@ -19,6 +19,7 @@
package appeng.entity;
import java.util.List;
import java.util.Random;
import net.minecraft.block.BlockState;
import net.minecraft.block.material.Material;
@@ -42,6 +43,8 @@ import appeng.util.Platform;
public final class ChargedQuartzEntity extends AEBaseItemEntity {
private static final Random RANDOM = new Random();
public static EntityType<ChargedQuartzEntity> TYPE;
private int delay = 0;
@@ -135,9 +138,15 @@ public final class ChargedQuartzEntity extends AEBaseItemEntity {
}
materials.fluixCrystal().maybeStack(2).ifPresent(is -> {
final ItemEntity entity = new ItemEntity(this.world, this.getPosX(), this.getPosY(), this.getPosZ(),
is);
final double x = Math.floor(this.getPosX()) + .25d + RANDOM.nextDouble() * .5;
final double y = Math.floor(this.getPosY()) + .25d + RANDOM.nextDouble() * .5;
final double z = Math.floor(this.getPosZ()) + .25d + RANDOM.nextDouble() * .5;
final double xSpeed = RANDOM.nextDouble() * .25 - 0.125;
final double ySpeed = RANDOM.nextDouble() * .25 - 0.125;
final double zSpeed = RANDOM.nextDouble() * .25 - 0.125;
final ItemEntity entity = new ItemEntity(this.world, x, y, z, is);
entity.setMotion(xSpeed, ySpeed, zSpeed);
this.world.addEntity(entity);
});
@@ -140,8 +140,8 @@ public final class TinyTNTPrimedEntity extends TNTEntity implements IEntityAddit
return;
}
final Explosion ex = new Explosion(this.world, this, this.getPosX(), this.getPosY(), this.getPosZ(), 0.2f,
false, Mode.BREAK);
final Explosion ex = new Explosion(this.world, this, null, null, this.getPosX(), this.getPosY(), this.getPosZ(),
0.2f, false, Explosion.Mode.BREAK);
final AxisAlignedBB area = new AxisAlignedBB(this.getPosX() - 1.5, this.getPosY() - 1.5f, this.getPosZ() - 1.5,
this.getPosX() + 1.5, this.getPosY() + 1.5, this.getPosZ() + 1.5);
final List<Entity> list = this.world.getEntitiesWithinAABBExcludingEntity(this, area);
@@ -1,14 +0,0 @@
package appeng.hooks;
import net.minecraft.util.RegistryKey;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.server.ServerWorld;
public interface DynamicDimensions {
ServerWorld addWorld(RegistryKey<World> worldId, RegistryKey<DimensionType> dimensionTypeId,
ChunkGenerator chunkGenerator);
}
@@ -0,0 +1,127 @@
package appeng.hooks;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.BlockFaceUV;
import net.minecraft.client.renderer.model.BlockPartFace;
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.Direction;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation;
import appeng.core.AppEng;
import appeng.mixins.unlitquad.BakedQuadAccessor;
/**
* Implementation details of allowing quads to be defined as "unlit" in JSON
* models by specifying an "unlit" boolean property on the face.
*/
public class UnlitQuadHooks {
/**
* Offset into the vertex data (which is represented as integers).
*/
private static final int LIGHT_OFFSET = getLightOffset();
// Lightmap texture coordinate with full intensity light leading to no drop in
// brightness
private static final int UNLIT_LIGHT_UV = LightTexture.packLight(15, 15);
/**
* Thread-Local flag to indicate that an enhanced Applied Energistics model is
* currently being deserialized.
*/
private static final ThreadLocal<Boolean> ENABLE_UNLIT_EXTENSIONS = new ThreadLocal<>();
/**
* Notify the unlit model system that a specific model is about to be
* deserialized by {@link net.minecraft.client.renderer.model.ModelBakery}.
*/
public static void beginDeserializingModel(ResourceLocation location) {
String namespace = location.getNamespace();
if (namespace.equals(AppEng.MOD_ID)) {
ENABLE_UNLIT_EXTENSIONS.set(true);
}
}
/**
* Notify the unlit model system that deserialization of a model has ended.
*/
public static void endDeserializingModel() {
ENABLE_UNLIT_EXTENSIONS.set(false);
}
public static boolean isUnlitExtensionEnabled() {
Boolean b = ENABLE_UNLIT_EXTENSIONS.get();
return b != null && b;
}
public static BlockPartFace enhanceModelElementFace(BlockPartFace modelElement, JsonElement jsonElement) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (JSONUtils.getBoolean(jsonObject, "unlit", false)) {
return new UnlitBlockPartFace(modelElement.cullFace, modelElement.tintIndex, modelElement.texture,
modelElement.blockFaceUV);
}
return modelElement;
}
/**
* Creates a new quad from the given quad and pre-bakes it to not be affected by
* lighting (neither diffuse lighting nor the prebaked lightmap). This works on
* the assumption that Vanilla will not modify a quad's lightmap data if it's
* not zero.
*/
public static BakedQuad makeUnlit(BakedQuad quad) {
int[] vertexData = quad.getVertexData().clone();
int stride = DefaultVertexFormats.BLOCK.getIntegerSize();
// Set the pre-baked texture coords for the lightmap.
// Vanilla will not overwrite them if they are non-zero
for (int i = 0; i < 4; i++) {
vertexData[stride * i + LIGHT_OFFSET] = UNLIT_LIGHT_UV;
}
TextureAtlasSprite sprite = ((BakedQuadAccessor) quad).getSprite();
// Copy the quad to disable diffuse lighting
return new BakedQuad(vertexData, quad.getTintIndex(), quad.getFace(), sprite, false /* diffuse lighting */);
}
/**
* This subclass is used as a marker to indicate this face deserialized from
* JSON is supposed to be unlit, which translates to processing by
* {@link #makeUnlit(BakedQuad)}.
*/
public static class UnlitBlockPartFace extends BlockPartFace {
public UnlitBlockPartFace(Direction cullFaceIn, int tintIndexIn, String textureIn, BlockFaceUV blockFaceUVIn) {
super(cullFaceIn, tintIndexIn, textureIn, blockFaceUVIn);
}
}
/**
* Find the index in the BakedQuad vertex data (for vertex 0) where the lightmap
* coordinates are. Assumes the BLOCK vertex format.
*/
private static int getLightOffset() {
VertexFormat format = DefaultVertexFormats.BLOCK;
int offset = 0;
for (VertexFormatElement element : format.getElements()) {
// TEX_2SB is the lightmap vertex element
if (element == DefaultVertexFormats.TEX_2SB) {
if (element.getType() != VertexFormatElement.Type.SHORT) {
throw new UnsupportedOperationException("Expected light map format to be of type SHORT");
}
if (offset % 4 != 0) {
throw new UnsupportedOperationException("Expected light map offset to be 4-byte aligned");
}
return offset / 4;
}
offset += element.getSize();
}
throw new UnsupportedOperationException("Failed to find the lightmap index in the block vertex format");
}
}
@@ -37,7 +37,7 @@ public enum TheOneProbeText {
}
public String getUnlocalized() {
return this.root + '.' + this.name().toLowerCase(Locale.ENGLISH);
return this.root + '.' + this.name().toLowerCase(Locale.ROOT);
}
}
@@ -29,12 +29,10 @@ import net.minecraft.block.material.Material;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemModelsProperties;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.IItemProvider;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
@@ -0,0 +1,29 @@
package appeng.items.misc;
import net.minecraft.item.Item;
import net.minecraft.item.ItemModelsProperties;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import appeng.bootstrap.components.IClientSetupComponent;
/**
* Exposes a predicate "growth", which is used in the item model to
* differentiate the growth stages.
*/
public class CrystalSeedRendering implements IClientSetupComponent {
private final Item item;
public CrystalSeedRendering(Item item) {
this.item = item;
}
@Override
@OnlyIn(Dist.CLIENT)
public void setup() {
// Expose the growth of the seed to the model system
ItemModelsProperties.func_239418_a_(item, new ResourceLocation("appliedenergistics2:growth"),
(is, w, p) -> CrystalSeedItem.getGrowthTicks(is) / (float) CrystalSeedItem.GROWTH_TICKS_REQUIRED);
}
}
@@ -307,14 +307,27 @@ public class EncodedPatternItem extends AEBaseItem {
final ListNBT tagIn = new ListNBT();
final ListNBT tagOut = new ListNBT();
boolean hasInput = false;
for (final ItemStack i : in) {
tagIn.add(createItemTag(i));
if (!i.isEmpty()) {
hasInput = true;
}
}
Preconditions.checkArgument(hasInput, "cannot encode a pattern that has no inputs.");
boolean hasNonEmptyOutput = false;
for (final ItemStack i : out) {
tagOut.add(createItemTag(i));
if (!i.isEmpty()) {
hasNonEmptyOutput = true;
}
}
// Patterns without any outputs are corrupt! Never encode such a pattern.
Preconditions.checkArgument(hasNonEmptyOutput, "cannot encode a pattern that has no output.");
encodedValue.put(EncodedPatternItem.NBT_INGREDIENTS, tagIn);
encodedValue.put(EncodedPatternItem.NBT_PRODUCTS, tagOut);
return encodedValue;
@@ -18,35 +18,40 @@
package appeng.items.storage;
import java.time.Instant;
import java.util.List;
import java.util.Locale;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.Constants;
import appeng.api.implementations.TransitionResult;
import appeng.api.implementations.items.ISpatialStorageCell;
import appeng.api.storage.ISpatialDimension;
import appeng.api.util.WorldCoord;
import appeng.core.AELog;
import appeng.core.localization.GuiText;
import appeng.items.AEBaseItem;
import appeng.spatial.SpatialDimensionManager;
import appeng.spatial.StorageHelper;
import appeng.spatial.SpatialStorageHelper;
import appeng.spatial.SpatialStoragePlot;
import appeng.spatial.SpatialStoragePlotManager;
import appeng.spatial.TransitionInfo;
public class SpatialStorageCellItem extends AEBaseItem implements ISpatialStorageCell {
private static final String TAG_DIMENSION_ID = "dimension_id";
private static final String TAG_PLOT_ID = "plot_id";
/**
* This is only stored in the itemstack to display in the tooltip on the
* client-side.
*/
private static final String TAG_PLOT_SIZE = "plot_size";
private final int maxRegion;
@@ -59,18 +64,22 @@ public class SpatialStorageCellItem extends AEBaseItem implements ISpatialStorag
@Override
public void addInformation(final ItemStack stack, final World world, final List<ITextComponent> lines,
final ITooltipFlag advancedTooltips) {
final RegistryKey<World> worldId = this.getStoredDimension(stack);
if (worldId == null) {
int plotId = this.getAllocatedPlotId(stack);
if (plotId == -1) {
lines.add(GuiText.Unformatted.text().deepCopy().mergeStyle(TextFormatting.ITALIC));
lines.add(GuiText.SpatialCapacity.text(maxRegion, maxRegion, maxRegion));
} else {
SpatialDimensionManager.INSTANCE.addCellDimensionTooltip(worldId, lines);
return;
}
if (advancedTooltips.isAdvanced()) {
if (worldId != null && worldId.func_240901_a_() != null) {
lines.add(new StringTextComponent("Dimension: " + worldId.func_240901_a_()));
}
// Add a serial number to allows players to keep different cells apart
// Try to make this a little more flavorful.
String serialNumber = String.format(Locale.ROOT, "SP-%04d", plotId);
lines.add(GuiText.SerialNumber.text(serialNumber));
CompoundNBT tag = stack.getTag();
if (tag != null && tag.contains(TAG_PLOT_SIZE, Constants.NBT.TAG_LONG)) {
BlockPos size = BlockPos.fromLong(tag.getLong(TAG_PLOT_SIZE));
lines.add(GuiText.StoredSize.text(size.getX(), size.getY(), size.getZ()));
}
}
@@ -85,70 +94,80 @@ public class SpatialStorageCellItem extends AEBaseItem implements ISpatialStorag
}
@Override
public RegistryKey<World> getStoredDimension(final ItemStack is) {
public int getAllocatedPlotId(final ItemStack is) {
final CompoundNBT c = is.getTag();
if (c != null && c.contains(TAG_DIMENSION_ID)) {
if (c != null && c.contains(TAG_PLOT_ID)) {
try {
ResourceLocation worldId = new ResourceLocation(c.getString(TAG_DIMENSION_ID));
return RegistryKey.func_240903_a_(Registry.WORLD_KEY, worldId);
int plotId = c.getInt(TAG_PLOT_ID);
if (SpatialStoragePlotManager.INSTANCE.getPlot(plotId) == null) {
return -1;
}
return plotId;
} catch (Exception e) {
AELog.warn("Failed to retrieve storage cell dimension.", e);
AELog.warn("Failed to retrieve spatial storage dimension: %s", e);
}
}
return null;
return -1;
}
@Override
public TransitionResult doSpatialTransition(final ItemStack is, final ServerWorld w, final WorldCoord min,
public boolean doSpatialTransition(final ItemStack is, final ServerWorld w, final WorldCoord min,
final WorldCoord max, int playerId) {
final int targetX = max.x - min.x - 1;
final int targetY = max.y - min.y - 1;
final int targetZ = max.z - min.z - 1;
final int maxSize = this.getMaxStoredDim(is);
if (targetX > maxSize && targetY > maxSize && targetZ > maxSize) {
AELog.info(
"Failing spatial transition because the transfer area (%dx%dx%d) exceeds the cell capacity (%s).",
targetX, targetY, targetZ, maxSize);
return false;
}
final BlockPos targetSize = new BlockPos(targetX, targetY, targetZ);
ISpatialDimension manager = SpatialDimensionManager.INSTANCE;
SpatialStoragePlotManager manager = SpatialStoragePlotManager.INSTANCE;
RegistryKey<World> worldId = this.getStoredDimension(is);
if (worldId == null || manager.getWorld(worldId) == null) {
worldId = manager.createNewCellDimension(targetSize);
SpatialStoragePlot plot = SpatialStoragePlotManager.INSTANCE.getPlot(this.getAllocatedPlotId(is));
if (plot != null) {
// Check that the existing plot has the right size
if (!plot.getSize().equals(targetSize)) {
AELog.info(
"Failing spatial transition because the transfer area (%dx%dx%d) does not match the spatial storage plot's size (%s).",
targetX, targetY, targetZ, plot.getSize());
return false;
}
} else {
// Otherwise allocate a new one
plot = manager.allocatePlot(targetSize, playerId);
}
if (worldId == null) {
// Failed to create the dimension
return new TransitionResult(false, 0);
}
// Store some information about this transition in the plot
TransitionInfo info = new TransitionInfo(w.func_234923_W_().func_240901_a_(), min.getBlockPos(),
max.getBlockPos(), Instant.now());
manager.setLastTransition(plot.getId(), info);
try {
if (manager.isCellDimension(worldId)) {
ServerWorld cellWorld = manager.getWorld(worldId);
ServerWorld cellWorld = manager.getWorld();
BlockPos scale = manager.getCellDimensionSize(worldId);
BlockPos offset = plot.getOrigin();
if (scale.equals(targetSize)) {
if (targetX <= maxSize && targetY <= maxSize && targetZ <= maxSize) {
BlockPos offset = manager.getCellDimensionOrigin(worldId);
this.setStoredDimension(is, plot.getId(), plot.getSize());
SpatialStorageHelper.getInstance().swapRegions(w, min.x + 1, min.y + 1, min.z + 1, cellWorld, offset.getX(),
offset.getY(), offset.getZ(), targetX - 1, targetY - 1, targetZ - 1);
this.setStoredDimension(is, worldId);
StorageHelper.getInstance().swapRegions(w, min.x + 1, min.y + 1, min.z + 1, cellWorld,
offset.getX(), offset.getY(), offset.getZ(), targetX - 1, targetY - 1, targetZ - 1);
return new TransitionResult(true, 0);
}
}
}
return new TransitionResult(false, 0);
return true;
} finally {
// clean up newly created dimensions that failed transfer
if (manager.isCellDimension(worldId) && this.getStoredDimension(is) == null) {
manager.deleteCellDimension(worldId);
if (this.getAllocatedPlotId(is) == -1) {
manager.freePlot(plot.getId(), true);
}
}
}
private void setStoredDimension(final ItemStack is, RegistryKey<World> worldId) {
public void setStoredDimension(final ItemStack is, int plotId, BlockPos size) {
final CompoundNBT c = is.getOrCreateTag();
c.putString(TAG_DIMENSION_ID, worldId.func_240901_a_().toString());
c.putInt(TAG_PLOT_ID, plotId);
c.putLong(TAG_PLOT_SIZE, size.toLong());
}
}
@@ -32,7 +32,6 @@ import net.minecraft.block.BlockState;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemModelsProperties;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.item.SnowballItem;
@@ -69,7 +68,6 @@ import appeng.block.networking.CableBusBlock;
import appeng.block.paint.PaintSplotchesBlock;
import appeng.core.AEConfig;
import appeng.core.Api;
import appeng.core.AppEng;
import appeng.core.localization.GuiText;
import appeng.helpers.IMouseWheelItem;
import appeng.hooks.IBlockTool;
-1
View File
@@ -176,7 +176,6 @@ public class Grid implements IGrid {
}
gridNode.getGridProxy().gridChanged();
// postEventTo( gridNode, networkChanged );
}
@Override
+1 -1
View File
@@ -502,7 +502,7 @@ public class EnergyGridCache implements IEnergyGrid {
private void removeRequester(IAEPowerStorage requester) {
Preconditions.checkState(!ongoingInjectOperation,
"Cannot modify energy requesters while energy is being injected.");
this.requesters.add(requester);
this.requesters.remove(requester);
}
private void addProvider(IAEPowerStorage provider) {
@@ -1,105 +0,0 @@
package appeng.mixins;
import java.util.Map;
import java.util.concurrent.Executor;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.server.IDynamicRegistries;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.Dimension;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.border.IBorderListener;
import net.minecraft.world.border.WorldBorder;
import net.minecraft.world.chunk.listener.IChunkStatusListener;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.settings.DimensionGeneratorSettings;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.DerivedWorldInfo;
import net.minecraft.world.storage.IServerConfiguration;
import net.minecraft.world.storage.IServerWorldInfo;
import net.minecraft.world.storage.SaveFormat;
import appeng.hooks.DynamicDimensions;
@Mixin(MinecraftServer.class)
public class MinecraftServerMixin implements DynamicDimensions {
@Shadow()
private IDynamicRegistries.Impl field_240767_f_;
@Shadow
private Map<RegistryKey<World>, ServerWorld> worlds;
@Shadow
private IServerConfiguration field_240768_i_;
@Shadow
private Executor backgroundExecutor;
@Shadow
private SaveFormat.LevelSave anvilConverterForAnvilFile;
public ServerWorld addWorld(RegistryKey<World> worldId, RegistryKey<DimensionType> dimensionTypeId,
ChunkGenerator chunkGenerator) {
Preconditions.checkArgument(!worlds.containsKey(worldId), "World with id %s already exists.",
worldId.func_240901_a_());
// Each worlds must have a corresponding dimension options, otherwise they will
// not be re-created on load
DimensionGeneratorSettings generatorOptions = this.field_240768_i_.getDimensionGeneratorSettings();
Preconditions.checkArgument(!generatorOptions.func_236224_e_().containsKey(worldId.func_240901_a_()),
"Dimension config with id %s already exists.", worldId.func_240901_a_());
DimensionType dimensionType = field_240767_f_.func_230520_a_().getValueForKey(dimensionTypeId);
Preconditions.checkArgument(dimensionType != null, "dimensionTypeId %s is not registered", dimensionTypeId);
// Create dimension options with the given world-id and chunk generator
Dimension dimensionOptions = new Dimension(
() -> field_240767_f_.func_230520_a_().getValueForKey(dimensionTypeId), chunkGenerator);
IServerWorldInfo serverWorldProperties = this.field_240768_i_.func_230407_G_();
// This sucks a little, but during startup, the server will use the same
// listener for every world,
// but it is ultimately only stored in the chunk storage. So we retrieve it from
// the overworld to
// mirror the original code as much as possible
ServerWorld overworld = worlds.get(ServerWorld.field_234918_g_);
Preconditions.checkState(overworld != null, "Overworld does not exist!");
IChunkStatusListener worldGenerationProgressListener = ((ThreadedAnvilChunkStorageAccessor) overworld
.getChunkProvider().chunkManager).getWorldGenerationProgressListener();
// Inherit seed + WorldBorder from overworld
long seed = overworld.getSeed();
WorldBorder worldBorder = overworld.getWorldBorder();
MinecraftServer self = (MinecraftServer) (Object) this;
DerivedWorldInfo unmodifiableLevelProperties = new DerivedWorldInfo(this.field_240768_i_,
serverWorldProperties);
ServerWorld world = new ServerWorld(self, this.backgroundExecutor, this.anvilConverterForAnvilFile,
unmodifiableLevelProperties, worldId, dimensionTypeId, dimensionType, worldGenerationProgressListener,
chunkGenerator, false, seed, ImmutableList.of(), false);
worldBorder.addListener(new IBorderListener.Impl(world.getWorldBorder()));
this.worlds.put(worldId, world);
// Adding it here will cause the world to be re-created on server restart
RegistryKey<Dimension> dimOptKey = RegistryKey.func_240903_a_(Registry.DIMENSION_KEY, worldId.func_240901_a_());
generatorOptions.func_236224_e_().register(dimOptKey, dimensionOptions);
generatorOptions.func_236224_e_().func_239662_d_(dimOptKey); // Otherwise it wont be saved
// Ensure the save properties are saved, or the world will potentially be lost
// on restart
this.anvilConverterForAnvilFile.func_237288_a_(this.field_240767_f_, this.field_240768_i_,
self.getPlayerList().getHostPlayerData());
return world;
}
}
@@ -0,0 +1,38 @@
package appeng.mixins.spatial;
import java.util.List;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import net.minecraft.util.RegistryKey;
import net.minecraft.world.Dimension;
import appeng.spatial.SpatialStorageDimensionIds;
/**
* This Mixin tries to hide the screen that warns users about experimental
* features being used, but only if AE2's dimension is the only added dimension.
*/
@Mixin(Dimension.class)
public class DimensionOptionMixin {
/**
* This injects right after the method makes a local copy of all present
* dimensions, and modifies the list by removing our mod-provided dimension from
* it.
* <p>
* This means Vanilla will perform it's check whether it should display an
* experimental warning without considering our dimension.
*/
@ModifyVariable(method = "func_236060_a_", at = @At(value = "INVOKE_ASSIGN", ordinal = 0, target = "Lcom/google/common/collect/Lists;newArrayList(Ljava/lang/Iterable;)Ljava/util/ArrayList;", remap = false), allow = 1)
private static List<Map.Entry<RegistryKey<Dimension>, Dimension>> overrideExperimentalCheck(
List<Map.Entry<RegistryKey<Dimension>, Dimension>> dimensions) {
// this only removes our dimension from the check
dimensions.removeIf(e -> e.getKey() == SpatialStorageDimensionIds.DIMENSION_ID);
return dimensions;
}
}
@@ -1,4 +1,4 @@
package appeng.mixins;
package appeng.mixins.spatial;
import java.util.OptionalLong;
@@ -11,15 +11,20 @@ import net.minecraft.server.IDynamicRegistries;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.DimensionType;
import appeng.spatial.SpatialDimensionManager;
import appeng.spatial.SpatialStorageDimensionIds;
/**
* Adds the storage cell world dimension type as a built-in dimension type. This
* can be registered as a JSON file as well, but doing so will trigger an
* experimental feature warning when the world is being loaded.
*/
@Mixin(value = DimensionType.class)
public class DimensionTypeMixin {
@Inject(method = "func_236027_a_", at = @At("TAIL"))
private static void addRegistryDefaults(IDynamicRegistries.Impl registryTracker, CallbackInfoReturnable<?> cir) {
registryTracker.func_239774_a_(SpatialDimensionManager.STORAGE_DIMENSION_TYPE,
registryTracker.func_239774_a_(SpatialStorageDimensionIds.DIMENSION_TYPE_ID,
new DimensionType(OptionalLong.of(12000), false, false, false, false, false, false, true, false, false,
256, BlockTags.INFINIBURN_OVERWORLD.getName(), 1.0f));
@@ -1,4 +1,4 @@
package appeng.mixins;
package appeng.mixins.spatial;
import java.util.Optional;
@@ -11,8 +11,8 @@ import net.minecraft.client.world.DimensionRenderInfo;
import net.minecraft.util.RegistryKey;
import net.minecraft.world.DimensionType;
import appeng.spatial.SpatialDimensionManager;
import appeng.spatial.StorageSkyProperties;
import appeng.spatial.SpatialStorageDimensionIds;
import appeng.spatial.SpatialStorageSkyProperties;
@Mixin(DimensionRenderInfo.class)
public class SkyPropertiesMixin {
@@ -20,8 +20,8 @@ public class SkyPropertiesMixin {
@Inject(method = "func_239215_a_", at = @At("HEAD"), cancellable = true)
private static void byDimensionType(Optional<RegistryKey<DimensionType>> optional,
CallbackInfoReturnable<DimensionRenderInfo> ci) {
if (optional.orElse(null) == SpatialDimensionManager.STORAGE_DIMENSION_TYPE) {
ci.setReturnValue(StorageSkyProperties.INSTANCE);
if (optional.orElse(null) == SpatialStorageDimensionIds.DIMENSION_TYPE_ID) {
ci.setReturnValue(SpatialStorageSkyProperties.INSTANCE);
}
}
@@ -1,4 +1,4 @@
package appeng.mixins;
package appeng.mixins.spatial;
import com.mojang.blaze3d.matrix.MatrixStack;
@@ -12,7 +12,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.WorldRenderer;
import appeng.client.render.SpatialSkyRender;
import appeng.spatial.SpatialDimensionManager;
import appeng.spatial.SpatialStorageDimensionIds;
@Mixin(value = WorldRenderer.class)
public class SkyRenderMixin {
@@ -23,7 +23,7 @@ public class SkyRenderMixin {
@SuppressWarnings("ConstantConditions")
@Inject(method = "renderSky(Lcom/mojang/blaze3d/matrix/MatrixStack;F)V", at = @At("HEAD"), cancellable = true)
public void renderSky(MatrixStack matrices, float tickDelta, CallbackInfo ci) {
if (mc.world.func_234922_V_() == SpatialDimensionManager.STORAGE_DIMENSION_TYPE) {
if (mc.world.func_234922_V_() == SpatialStorageDimensionIds.DIMENSION_TYPE_ID) {
SpatialSkyRender.getInstance().render(matrices);
ci.cancel();
}
@@ -0,0 +1,15 @@
package appeng.mixins.unlitquad;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@Mixin(BakedQuad.class)
public interface BakedQuadAccessor {
@Accessor
TextureAtlasSprite getSprite();
}
@@ -0,0 +1,37 @@
package appeng.mixins.unlitquad;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.BlockModel;
import net.minecraft.client.renderer.model.BlockPart;
import net.minecraft.client.renderer.model.BlockPartFace;
import net.minecraft.client.renderer.model.IModelTransform;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import appeng.hooks.UnlitQuadHooks;
/**
* This mixin hooks into conversion from {@link BlockPartFace} to
* {@link BakedQuad} to apply our unlit extensions if the block part face is an
* instance of our marker class
* {@link appeng.hooks.UnlitQuadHooks.UnlitBlockPartFace}.
*/
@Mixin(BlockModel.class)
public class BlockModelMixin {
@Inject(method = "bakeFace", at = @At("RETURN"), cancellable = true, require = 1, allow = 1)
private static void onBakeFace(BlockPart partIn, BlockPartFace partFaceIn, TextureAtlasSprite spriteIn,
Direction directionIn, IModelTransform transformIn, ResourceLocation locationIn,
CallbackInfoReturnable<BakedQuad> cri) {
if (partFaceIn instanceof UnlitQuadHooks.UnlitBlockPartFace) {
cri.setReturnValue(UnlitQuadHooks.makeUnlit(cri.getReturnValue()));
}
}
}
@@ -0,0 +1,35 @@
package appeng.mixins.unlitquad;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.client.renderer.model.BlockPartFace;
import appeng.hooks.UnlitQuadHooks;
/**
* This mixin will call the hook to deserialize the unlit property, but only if
* we are currently deserializing an AE2 model.
*/
@Mixin(BlockPartFace.Deserializer.class)
public class BlockPartFaceDeserializerMixin {
@Inject(method = "deserialize", at = @At("RETURN"), cancellable = true, allow = 1, remap = false)
public void onDeserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext,
CallbackInfoReturnable<BlockPartFace> cri) {
if (!UnlitQuadHooks.isUnlitExtensionEnabled()) {
return; // Not in a model that activated the deserializer
}
BlockPartFace modelElement = cri.getReturnValue();
cri.setReturnValue(UnlitQuadHooks.enhanceModelElementFace(modelElement, jsonElement));
}
}
@@ -0,0 +1,34 @@
package appeng.mixins.unlitquad;
import java.io.IOException;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.client.renderer.model.BlockModel;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.util.ResourceLocation;
import appeng.hooks.UnlitQuadHooks;
/**
* The only job of this mixin is to only enable the unlit extensions if the
* model is whitelisted for it, which is decided in {@link UnlitQuadHooks}.
*/
@Mixin(ModelBakery.class)
public class ModelBakeryMixin {
@Inject(method = "loadModel", at = @At("HEAD"), allow = 1)
protected void onBeginLoadModel(ResourceLocation location, CallbackInfoReturnable<BlockModel> cri)
throws IOException {
UnlitQuadHooks.beginDeserializingModel(location);
}
@Inject(method = "loadModel", at = @At("RETURN"))
protected void onEndLoadModel(ResourceLocation location, CallbackInfoReturnable<BlockModel> cri) {
UnlitQuadHooks.endDeserializingModel();
}
}
@@ -28,15 +28,11 @@ import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.client.model.data.IModelData;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartModel;
import appeng.api.util.AEPartLocation;
import appeng.items.parts.PartModels;
public class IdentityAnnihilationPlanePart extends AnnihilationPlanePart {
@@ -45,6 +45,11 @@ public class FEP2PTunnelPart extends P2PTunnelPart<FEP2PTunnelPart> {
super(is);
}
@Override
protected float getPowerDrainPerTick() {
return 2.0f;
}
@PartModels
public static List<IPartModel> getModels() {
return MODELS.getModels();
@@ -54,7 +54,8 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> {
return MODELS.getModels();
}
public float getPowerDrainPerTick() {
@Override
protected float getPowerDrainPerTick() {
return 2.0f;
}
@@ -68,6 +68,11 @@ public class ItemP2PTunnelPart extends P2PTunnelPart<ItemP2PTunnelPart> implemen
super(is);
}
@Override
protected float getPowerDrainPerTick() {
return POWER_DRAIN;
}
@Override
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
this.cachedInv = null;
@@ -235,10 +240,6 @@ public class ItemP2PTunnelPart extends P2PTunnelPart<ItemP2PTunnelPart> implemen
return this.getDestination().getSlotLimit(slot);
}
public float getPowerDrainPerTick() {
return POWER_DRAIN;
}
@Override
public IPartModel getStaticModels() {
return MODELS.getModel(this.isPowered(), this.isActive());
@@ -56,6 +56,10 @@ public class LightP2PTunnelPart extends P2PTunnelPart<LightP2PTunnelPart> implem
super(is);
}
protected float getPowerDrainPerTick() {
return 0.5f;
}
@Override
public void chanRender(final MENetworkChannelsChanged c) {
this.onTunnelNetworkChange();
@@ -186,10 +190,6 @@ public class LightP2PTunnelPart extends P2PTunnelPart<LightP2PTunnelPart> implem
return this.doWork() ? TickRateModulation.URGENT : TickRateModulation.SLOWER;
}
public float getPowerDrainPerTick() {
return 0.5f;
}
@Override
public IPartModel getStaticModels() {
return MODELS.getModel(this.isPowered(), this.isActive());
@@ -67,6 +67,11 @@ public class MEP2PTunnelPart extends P2PTunnelPart<MEP2PTunnelPart> implements I
this.outerProxy.setFlags(GridFlags.DENSE_CAPACITY, GridFlags.CANNOT_CARRY_COMPRESSED);
}
@Override
protected float getPowerDrainPerTick() {
return 2.0f;
}
@Override
public void readFromNBT(final CompoundNBT extra) {
super.readFromNBT(extra);
@@ -61,6 +61,11 @@ public abstract class P2PTunnelPart<T extends P2PTunnelPart> extends BasicStateP
public P2PTunnelPart(final ItemStack is) {
super(is);
this.getProxy().setIdlePowerUsage(this.getPowerDrainPerTick());
}
protected float getPowerDrainPerTick() {
return 1.0f;
}
public TunnelCollection<T> getCollection(final Collection<P2PTunnelPart> collection,
@@ -55,6 +55,11 @@ public class RedstoneP2PTunnelPart extends P2PTunnelPart<RedstoneP2PTunnelPart>
super(is);
}
@Override
protected float getPowerDrainPerTick() {
return 0.5f;
}
@MENetworkEventSubscribe
public void changeStateA(final MENetworkBootingStatusChange bs) {
this.setNetworkReady();
@@ -123,10 +128,6 @@ public class RedstoneP2PTunnelPart extends P2PTunnelPart<RedstoneP2PTunnelPart>
this.setNetworkReady();
}
public float getPowerDrainPerTick() {
return 0.5f;
}
@Override
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
if (!this.isOutput()) {
@@ -20,7 +20,6 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.registries.ForgeRegistryEntry;
import appeng.core.AEConfig;
import appeng.core.AppEng;
import appeng.core.sync.BasePacket;
public class GrinderRecipeSerializer extends ForgeRegistryEntry<IRecipeSerializer<?>>
@@ -14,7 +14,6 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.registries.ForgeRegistryEntry;
import appeng.api.features.InscriberProcessType;
import appeng.core.AppEng;
import appeng.core.sync.BasePacket;
public class InscriberRecipeSerializer extends ForgeRegistryEntry<IRecipeSerializer<?>>
+3 -1
View File
@@ -20,6 +20,8 @@ package appeng.server;
import static net.minecraft.command.Commands.literal;
import java.util.Locale;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
@@ -46,7 +48,7 @@ public final class AECommand {
private void add(LiteralArgumentBuilder<net.minecraft.command.CommandSource> builder, Commands subCommand) {
LiteralArgumentBuilder<CommandSource> subCommandBuilder = literal(subCommand.name().toLowerCase())
LiteralArgumentBuilder<CommandSource> subCommandBuilder = literal(subCommand.name().toLowerCase(Locale.ROOT))
.requires(src -> src.hasPermissionLevel(subCommand.level));
subCommand.command.addArguments(subCommandBuilder);
subCommandBuilder.executes(ctx -> {
+3 -1
View File
@@ -19,13 +19,15 @@
package appeng.server;
import appeng.server.subcommands.ChunkLogger;
import appeng.server.subcommands.SpatialStorageCommand;
import appeng.server.subcommands.Supporters;
import appeng.server.subcommands.TestMeteoritesCommand;
import appeng.server.subcommands.TestOreGenCommand;
public enum Commands {
Chunklogger(4, new ChunkLogger(), false), Supporters(0, new Supporters(), false),
TestOreGen(4, new TestOreGenCommand(), true), TestMeteorites(4, new TestMeteoritesCommand(), true);
TestOreGen(4, new TestOreGenCommand(), true), TestMeteorites(4, new TestMeteoritesCommand(), true),
Spatial(4, new SpatialStorageCommand(), false);
public final int level;
public final ISubCommand command;
@@ -0,0 +1,327 @@
package appeng.server.subcommands;
import static net.minecraft.command.Commands.literal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.function.UnaryOperator;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.command.CommandException;
import net.minecraft.command.CommandSource;
import net.minecraft.command.Commands;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.IFormattableTextComponent;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import appeng.core.Api;
import appeng.core.worlddata.WorldData;
import appeng.items.storage.SpatialStorageCellItem;
import appeng.server.ISubCommand;
import appeng.spatial.SpatialStorageDimensionIds;
import appeng.spatial.SpatialStoragePlot;
import appeng.spatial.SpatialStoragePlotManager;
import appeng.spatial.TransitionInfo;
/**
* This admin command allows management of spatial storage plots.
*/
public class SpatialStorageCommand implements ISubCommand {
@Override
public void addArguments(LiteralArgumentBuilder<CommandSource> builder) {
// Shows info about a given plot or about the plot the player is currently in
builder.then(literal("info").executes(ctx -> {
showPlotInfo(ctx.getSource(), getCurrentPlot(ctx.getSource()));
return 1;
}).then(Commands.argument("plotId", IntegerArgumentType.integer(1)).executes(ctx -> {
int plotId = IntegerArgumentType.getInteger(ctx, "plotId");
showPlotInfo(ctx.getSource(), getPlot(plotId));
return 1;
})));
// Teleport into the plot
builder.then(literal("tp").then(Commands.argument("plotId", IntegerArgumentType.integer(1)).executes(ctx -> {
int plotId = IntegerArgumentType.getInteger(ctx, "plotId");
teleportToPlot(ctx.getSource(), plotId);
return 1;
})));
// Teleport from the current plot back to the source of its content, or do the
// same for a given plot id
builder.then(literal("tpback").executes(ctx -> {
teleportBack(ctx.getSource());
return 1;
}).then(Commands.argument("plotId", IntegerArgumentType.integer(1)).executes(ctx -> {
int plotId = IntegerArgumentType.getInteger(ctx, "plotId");
teleportBack(ctx.getSource(), getPlot(plotId));
return 1;
})));
// Creates a storage cell for the given plot id and gives it to the player
builder.then(
literal("givecell").then(Commands.argument("plotId", IntegerArgumentType.integer(1)).executes(ctx -> {
int plotId = IntegerArgumentType.getInteger(ctx, "plotId");
giveCell(ctx.getSource(), plotId);
return 1;
})));
}
/**
* If the player is currently within a spatial storage plot, teleports them back
* to the last source of transition.
*/
private void teleportBack(CommandSource source) {
if (source.getWorld().func_234923_W_() != SpatialStorageDimensionIds.WORLD_ID) {
throw new CommandException(new StringTextComponent("Must be within the spatial storage world."));
}
BlockPos playerPos = new BlockPos(source.getPos());
int x = playerPos.getX();
int z = playerPos.getZ();
// This is slow, but for an admin-command it's acceptable
for (SpatialStoragePlot plot : SpatialStoragePlotManager.INSTANCE.getPlots()) {
BlockPos origin = plot.getOrigin();
BlockPos size = plot.getSize();
if (x >= origin.getX() && x <= origin.getX() + size.getX() && z >= origin.getZ()
&& z <= origin.getZ() + size.getZ()) {
teleportBack(source, plot);
return;
}
}
throw new CommandException(ITextComponent.func_241827_a_("Couldn't find a plot for the current position."));
}
/**
* Teleports back from the given plot.
*/
private void teleportBack(CommandSource source, SpatialStoragePlot plot) {
TransitionInfo lastTransition = plot.getLastTransition();
if (lastTransition == null) {
throw new CommandException(
ITextComponent.func_241827_a_("This plot doesn't have a last known transition."));
}
String command = getTeleportCommand(lastTransition.getWorldId(), lastTransition.getMin().add(0, 1, 0));
runCommandFor(source, command);
}
/**
* Shows detailed information about a spatial storage plot.
*/
private static void showPlotInfo(CommandSource source, SpatialStoragePlot plot) {
sendKeyValuePair(source, "Plot ID", String.valueOf(plot.getId()));
// Show the owner of the spatial storage plot
int playerId = plot.getOwner();
if (playerId != -1) {
UUID profileId = WorldData.instance().playerData().getProfileId(playerId);
if (profileId == null) {
sendKeyValuePair(source, "Owner", "Unknown AE2 player (" + playerId + ")");
} else {
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
ServerPlayerEntity player = server.getPlayerList().getPlayerByUUID(profileId);
if (player == null) {
sendKeyValuePair(source, "Owner", "Unknown Minecraft profile (" + profileId + ")");
} else {
sendKeyValuePair(source, "Owner", player.getDisplayName());
}
}
} else {
sendKeyValuePair(source, "Owner", "Unknown");
}
sendKeyValuePair(source, "Size", formatBlockPos(plot.getSize(), "x"));
// Show the plot's origin and make it clickable to teleport directly to it
String teleportToPlotCommand = getTeleportCommand(SpatialStorageDimensionIds.WORLD_ID.func_240901_a_(),
plot.getOrigin());
sendKeyValuePair(source, "Origin", new StringTextComponent(formatBlockPos(plot.getOrigin(), ","))
.modifyStyle(makeCommandLink(teleportToPlotCommand, "Teleport into plot")));
sendKeyValuePair(source, "Region file:", plot.getRegionFilename());
// Show information about what was last transfered into the plot (with a
// clickable link to the source)
TransitionInfo lastTransition = plot.getLastTransition();
if (lastTransition != null) {
source.sendFeedback(new StringTextComponent("Last Transition:").mergeStyle(TextFormatting.UNDERLINE,
TextFormatting.BOLD), true);
String sourceWorldId = lastTransition.getWorldId().toString();
IFormattableTextComponent sourceLink = new StringTextComponent(
sourceWorldId + " - " + formatBlockPos(lastTransition.getMin(), ",") + " to "
+ formatBlockPos(lastTransition.getMax(), ","));
String tpCommand = getTeleportCommand(lastTransition.getWorldId(), lastTransition.getMin().add(0, 1, 0));
sourceLink.modifyStyle(makeCommandLink(tpCommand, "Click to teleport"));
sendKeyValuePair(source, "Source", sourceLink);
sendKeyValuePair(source, "When", lastTransition.getTimestamp().toString());
} else {
source.sendFeedback(new StringTextComponent("Last Transition unknown"), true);
}
}
private static void teleportToPlot(CommandSource source, int plotId) {
SpatialStoragePlot plot = getPlot(plotId);
String teleportCommand = getTeleportCommand(SpatialStorageDimensionIds.WORLD_ID.func_240901_a_(),
plot.getOrigin());
runCommandFor(source, teleportCommand);
}
private void giveCell(CommandSource source, int plotId) throws CommandSyntaxException {
ServerPlayerEntity player = source.asPlayer();
SpatialStoragePlot plot = getPlot(plotId);
ItemStack cell;
int longestSide = getLongestSide(plot.getSize());
if (longestSide <= 2) {
cell = Api.instance().definitions().items().spatialCell2().stack(1);
} else if (longestSide <= 16) {
cell = Api.instance().definitions().items().spatialCell16().stack(1);
} else {
cell = Api.instance().definitions().items().spatialCell128().stack(1);
}
if (!(cell.getItem() instanceof SpatialStorageCellItem)) {
throw new CommandException(
ITextComponent.func_241827_a_("Storage cell items don't implement the storage cell interface!"));
}
SpatialStorageCellItem spatialCellItem = (SpatialStorageCellItem) cell.getItem();
spatialCellItem.setStoredDimension(cell, plotId, plot.getSize());
player.addItemStackToInventory(cell);
}
private static int getLongestSide(BlockPos size) {
return Math.max(size.getX(), Math.max(size.getY(), size.getZ()));
}
@Override
public void call(MinecraftServer srv, CommandContext<CommandSource> ctx, CommandSource sender) {
List<SpatialStoragePlot> plots = new ArrayList<>(SpatialStoragePlotManager.INSTANCE.getPlots());
// Prints the least recently used plots
plots.sort(Comparator.comparing((SpatialStoragePlot plot) -> {
TransitionInfo lastTransition = plot.getLastTransition();
if (lastTransition != null) {
return lastTransition.getTimestamp();
} else {
return Instant.MIN;
}
}).reversed());
for (int i = 0; i < Math.min(5, plots.size()); i++) {
SpatialStoragePlot plot = plots.get(i);
String size = formatBlockPos(plot.getSize(), "x");
BlockPos originPos = plot.getOrigin();
String origin = formatBlockPos(originPos, ",");
ITextComponent infoLink = new StringTextComponent("Plot #" + plot.getId())
.modifyStyle(makeCommandLink("/ae2 spatial info " + plot.getId(), "Click to show details"));
ITextComponent tpLink = new StringTextComponent("Origin: " + origin)
.modifyStyle(makeCommandLink("/ae2 spatial tp " + plot.getId(), "Click to teleport into plot"));
IFormattableTextComponent message = new StringTextComponent("").append(infoLink)
.appendString(" Size: " + size + " ").append(tpLink);
sender.sendFeedback(message, true);
}
}
private static String formatBlockPos(BlockPos size, String separator) {
return size.getX() + separator + size.getY() + separator + size.getZ();
}
private static UnaryOperator<Style> makeCommandLink(String command, String tooltip) {
return style -> style.applyFormatting(TextFormatting.UNDERLINE)
.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command))
.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent(tooltip)));
}
private static void runCommandFor(CommandSource source, String command) {
Commands commandManager = ServerLifecycleHooks.getCurrentServer().getCommandManager();
commandManager.handleCommand(source, command);
}
private static String getTeleportCommand(ResourceLocation worldId, BlockPos pos) {
return "/execute in " + worldId + " run tp @s " + pos.getX() + " " + (pos.getY() + 1) + " " + pos.getZ();
}
private static SpatialStoragePlot getPlot(int plotId) {
SpatialStoragePlot plot = SpatialStoragePlotManager.INSTANCE.getPlot(plotId);
if (plot == null) {
throw new CommandException(new StringTextComponent("Plot not found: " + plotId));
}
return plot;
}
private static void sendKeyValuePair(CommandSource source, String label, ITextComponent value) {
source.sendFeedback(
new StringTextComponent("")
.append(new StringTextComponent(label + ": ").mergeStyle(TextFormatting.BOLD)).append(value),
true);
}
private static void sendKeyValuePair(CommandSource source, String label, String value) {
sendKeyValuePair(source, label, new StringTextComponent(value));
}
/**
* Gets the spatial storage plot that the command source is currently in.
*/
private static SpatialStoragePlot getCurrentPlot(CommandSource source) {
if (source.getWorld().func_234923_W_() != SpatialStorageDimensionIds.WORLD_ID) {
throw new CommandException(new StringTextComponent("Must be within the spatial storage world."));
}
BlockPos playerPos = new BlockPos(source.getPos());
int x = playerPos.getX();
int z = playerPos.getZ();
// This is slow, but for an admin-command it's acceptable
for (SpatialStoragePlot plot : SpatialStoragePlotManager.INSTANCE.getPlots()) {
BlockPos origin = plot.getOrigin();
BlockPos size = plot.getSize();
if (x >= origin.getX() && x <= origin.getX() + size.getX() && z >= origin.getZ()
&& z <= origin.getZ() + size.getZ()) {
return plot;
}
}
throw new CommandException(ITextComponent.func_241827_a_("Couldn't find a plot for the current position."));
}
}
+14 -16
View File
@@ -34,9 +34,10 @@ import net.minecraft.world.ITickList;
import net.minecraft.world.NextTickListEntry;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.lighting.WorldLightManager;
import net.minecraft.world.server.ServerTickList;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.server.ServerWorldLightManager;
import appeng.api.movable.IMovableHandler;
import appeng.api.movable.IMovableRegistry;
@@ -300,12 +301,17 @@ public class CachedPlane {
private void updateChunks() {
WorldLightManager lightManager = world.getLightManager();
// update shit..
for (int x = 0; x < this.cx_size; x++) {
for (int z = 0; z < this.cz_size; z++) {
final Chunk c = this.myChunks[x][z];
// FIXME: Light shit
c.markDirty();
if (lightManager instanceof ServerWorldLightManager) {
ServerWorldLightManager serverLightManager = (ServerWorldLightManager) lightManager;
for (int x = 0; x < this.cx_size; x++) {
for (int z = 0; z < this.cz_size; z++) {
final Chunk c = this.myChunks[x][z];
serverLightManager.lightChunk(c, false);
c.markDirty();
}
}
}
@@ -317,17 +323,14 @@ public class CachedPlane {
WorldData.instance().compassData().service().updateArea(this.getWorld(), c);
// FIXME this was sending chunks to players...
SChunkDataPacket cdp = new SChunkDataPacket(c, verticalBits, false);
((ServerChunkProvider) world.getChunkProvider()).chunkManager.getTrackingPlayers(c.getPos(), false)
world.getChunkProvider().chunkManager.getTrackingPlayers(c.getPos(), false)
.forEach(spe -> spe.connection.sendPacket(cdp));
}
}
// FIXME check if this makes any sense at all to send changes to players asap
ServerChunkProvider serverChunkProvider = (ServerChunkProvider) world.getChunkProvider();
serverChunkProvider.tick(() -> false);
world.getChunkProvider().tick(() -> false);
}
List<WorldCoord> getUpdates() {
@@ -340,7 +343,6 @@ public class CachedPlane {
private static class BlockStorageData {
public BlockState state;
public int light;
}
private class Column {
@@ -373,8 +375,6 @@ public class CachedPlane {
final ChunkSection[] storage = this.c.getSections();
final ChunkSection extendedBlockStorage = storage[y >> 4];
extendedBlockStorage.setBlockState(this.x, y & 15, this.z, data.state);
// FIXME extendedBlockStorage.setBlockLight( this.x, y & 15, this.z, data.light
// );
}
private void fillData(final int y, BlockStorageData data) {
@@ -382,8 +382,6 @@ public class CachedPlane {
final ChunkSection extendedblockstorage = storage[y >> 4];
data.state = extendedblockstorage.getBlockState(this.x, y & 15, this.z);
// FIXME data.light = extendedblockstorage.getBlockLight( this.x, y & 15, this.z
// );
}
private boolean doNotSkip(final int y) {
@@ -1,70 +0,0 @@
package appeng.spatial;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.storage.WorldSavedData;
/**
* Helps with encoding and decoding the extra data we attach to each created
* storage dimension world as persistent state.
*/
public final class SpatialDimensionExtraData extends WorldSavedData {
/**
* ID of this data when it is attached to a world.
*/
public static final String ID = "ae2_spatial_info";
// Used to allow forward compatibility
private static final int CURRENT_FORMAT = 1;
private static final String TAG_FORMAT = "format";
private static final String TAG_SIZE = "size";
/**
* The storage size of this dimension. This is dicateted by the pylon structure
* size used to perform the first transfer into this dimension. Once it's set,
* it cannot be changed anymore.
*/
private BlockPos size = BlockPos.ZERO;
public SpatialDimensionExtraData() {
super(ID);
}
public SpatialDimensionExtraData(BlockPos size) {
super(ID);
this.size = size;
}
public BlockPos getSize() {
return size;
}
public void setSize(BlockPos size) {
this.size = size;
setDirty(true);
}
@Override
public void read(CompoundNBT tag) {
int version = tag.getInt(TAG_FORMAT);
if (version != CURRENT_FORMAT) {
// Currently no new format has been defined, as such anything but the current
// version is invalid
throw new IllegalStateException("Invalid AE2 spatial info version: " + version);
}
size = NBTUtil.readBlockPos(tag.getCompound(TAG_SIZE));
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putInt(TAG_FORMAT, CURRENT_FORMAT);
tag.put(TAG_SIZE, NBTUtil.writeBlockPos(size));
return tag;
}
}
@@ -1,201 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2017, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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.
*
* Applied Energistics 2 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 Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import appeng.api.storage.ISpatialDimension;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.core.localization.GuiText;
import appeng.hooks.DynamicDimensions;
public final class SpatialDimensionManager implements ISpatialDimension {
// A region file is 512x512 blocks (32x32 chunks),
// to avoid creating the 4 regions around 0,0,0,
// we move the origin to the middle of region 0,0
public static final BlockPos REGION_CENTER = new BlockPos(512 / 2, 64, 512 / 2);
public static final RegistryKey<DimensionType> STORAGE_DIMENSION_TYPE = RegistryKey
.func_240903_a_(Registry.DIMENSION_TYPE_KEY, AppEng.makeId("storage_cell"));
public static final ISpatialDimension INSTANCE = new SpatialDimensionManager();
private static final String DIM_ID_PREFIX = "spatial_";
private SpatialDimensionManager() {
}
@Override
public ServerWorld getWorld(RegistryKey<World> cellDim) {
MinecraftServer server = getServer();
return server.getWorld(cellDim);
}
@Override
public RegistryKey<World> createNewCellDimension(BlockPos size) {
ResourceLocation dimKey = findFreeDimensionId();
AELog.info("Allocating storage cell dimension '%s'", dimKey);
DynamicDimensions dynamicDimensions = (DynamicDimensions) getServer();
RegistryKey<World> worldId = RegistryKey.func_240903_a_(Registry.WORLD_KEY, dimKey);
ServerWorld world = dynamicDimensions.addWorld(worldId, STORAGE_DIMENSION_TYPE, StorageChunkGenerator.INSTANCE);
SpatialDimensionExtraData spatialExtraData = world.getSavedData().getOrCreate(SpatialDimensionExtraData::new,
SpatialDimensionExtraData.ID);
spatialExtraData.setSize(size);
return worldId;
}
/**
* Tries finding the next free storage cell dimension ID based on the currently
* registered storage cell dimensions.
*/
private ResourceLocation findFreeDimensionId() {
int maxId = 0;
for (RegistryKey<World> worldId : getServer().func_240770_D_()) {
ResourceLocation regName = worldId.func_240901_a_();
if (regName == null || !AppEng.MOD_ID.equals(regName.getNamespace())) {
continue;
}
String path = regName.getPath();
if (!path.startsWith(DIM_ID_PREFIX)) {
continue;
}
try {
String numericIdPart = path.substring(DIM_ID_PREFIX.length());
maxId = Math.max(Integer.parseUnsignedInt(numericIdPart), maxId);
} catch (NumberFormatException e) {
AELog.warn("Unparsable storage cell dimension id '%s'", path, e);
}
}
++maxId;
return AppEng.makeId(DIM_ID_PREFIX + maxId);
}
@Override
public void deleteCellDimension(RegistryKey<World> worldId) {
AELog.info("Unregistering storage cell dimension %s", worldId.func_240901_a_());
MinecraftServer server = getServer();
// FIXME FABRIC ServerWorld world = DimensionManager.getWorld(server, worldId, false, false);
// FIXME FABRIC if (world != null) {
// FIXME FABRIC DimensionManager.unloadWorld(world);
// FIXME FABRIC }
// FIXME FABRIC DimensionManager.unloadWorlds(server, true);
// FIXME FABRIC DimensionManager.unregisterDimension(worldId.getId());
throw new IllegalStateException();
}
@Override
public boolean isCellDimension(RegistryKey<World> worldId) {
ResourceLocation id = worldId.func_240901_a_();
if (!id.getNamespace().equals(AppEng.MOD_ID)) {
return false; // World belongs to a different mod
}
if (!id.getPath().startsWith(DIM_ID_PREFIX)) {
return false;
}
// Check that the world has the right dimension type
ServerWorld world = getServer().getWorld(worldId);
if (world == null) {
return false; // Non-existent world
}
return world.func_234922_V_().equals(STORAGE_DIMENSION_TYPE);
}
@Override
public BlockPos getCellDimensionOrigin(RegistryKey<World> worldId) {
return REGION_CENTER;
}
@Override
public BlockPos getCellDimensionSize(RegistryKey<World> worldId) {
SpatialDimensionExtraData extraData = getExtraData(worldId);
return extraData != null ? extraData.getSize() : BlockPos.ZERO;
}
@Override
public void addCellDimensionTooltip(RegistryKey<World> worldId, List<ITextComponent> lines) {
// Check if the cell dimension type is even registered
ResourceLocation registryName = worldId.func_240901_a_();
if (registryName == null || !AppEng.MOD_ID.equals(registryName.getNamespace())) {
return;
}
if (!registryName.getPath().startsWith(DIM_ID_PREFIX)) {
return;
}
// Add the actual stored size
BlockPos size = SpatialDimensionManager.INSTANCE.getCellDimensionSize(worldId);
lines.add(GuiText.StoredSize.text(size.getX(), size.getY(), size.getZ()));
// Add a serial number to allows players to keep different cells apart
int dimId;
try {
String numericIdPart = registryName.getPath().substring(DIM_ID_PREFIX.length());
dimId = Integer.parseUnsignedInt(numericIdPart);
} catch (NumberFormatException ignored) {
return;
}
// Try to make this a little more flavorful.
String serialNumber = String.format(Locale.ROOT, "SP-%04d", dimId);
lines.add(GuiText.SerialNumber.text(serialNumber));
}
@Nullable
private SpatialDimensionExtraData getExtraData(RegistryKey<World> worldId) {
ServerWorld world = getWorld(worldId);
if (world == null) {
return null;
}
return world.getSavedData().get(SpatialDimensionExtraData::new, SpatialDimensionExtraData.ID);
}
private static MinecraftServer getServer() {
return ServerLifecycleHooks.getCurrentServer();
}
}
@@ -25,11 +25,14 @@ import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class StorageCellBiome extends Biome {
/**
* The single biome used within the spatial storage world.
*/
public class SpatialStorageBiome extends Biome {
public static final StorageCellBiome INSTANCE = new StorageCellBiome();
public static final SpatialStorageBiome INSTANCE = new SpatialStorageBiome();
public StorageCellBiome() {
public SpatialStorageBiome() {
super(new Biome.Builder()
.surfaceBuilder(
new ConfiguredSurfaceBuilder<>(SurfaceBuilder.NOPE, SurfaceBuilder.STONE_STONE_GRAVEL_CONFIG))
@@ -43,18 +43,21 @@ import net.minecraft.world.gen.settings.DimensionStructuresSettings;
import appeng.core.Api;
public class StorageChunkGenerator extends ChunkGenerator {
/**
* Chunk generator the spatial storage world.
*/
public class SpatialStorageChunkGenerator extends ChunkGenerator {
private final Blockreader columnSample;
public static final StorageChunkGenerator INSTANCE = new StorageChunkGenerator();
public static final SpatialStorageChunkGenerator INSTANCE = new SpatialStorageChunkGenerator();
public static final Codec<StorageChunkGenerator> CODEC = RecordCodecBuilder
public static final Codec<SpatialStorageChunkGenerator> CODEC = RecordCodecBuilder
.create((instance) -> instance.stable(INSTANCE));
private final BlockState defaultBlockState;
private StorageChunkGenerator() {
private SpatialStorageChunkGenerator() {
super(createBiomeProvider(), createSettings());
this.defaultBlockState = Api.instance().definitions().blocks().matrixFrame().block().getDefaultState();
@@ -71,7 +74,7 @@ public class StorageChunkGenerator extends ChunkGenerator {
}
private static BiomeProvider createBiomeProvider() {
return new SingleBiomeProvider(StorageCellBiome.INSTANCE);
return new SingleBiomeProvider(SpatialStorageBiome.INSTANCE);
}
private static DimensionStructuresSettings createSettings() {
@@ -0,0 +1,57 @@
package appeng.spatial;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.Dimension;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import appeng.core.AppEng;
import appeng.mixins.spatial.DimensionTypeMixin;
/**
* IDs for the spatial storage world related dimension objects.
*/
public final class SpatialStorageDimensionIds {
/**
* ID of the {@link DimensionType} used for the spatial storage world.
* <p>
* This is defined in {@link DimensionTypeMixin}.
*/
public static final RegistryKey<DimensionType> DIMENSION_TYPE_ID = RegistryKey
.func_240903_a_(Registry.DIMENSION_TYPE_KEY, AppEng.makeId("spatial_storage"));
/**
* ID of the {@link net.minecraft.world.gen.ChunkGenerator} used for the spatial
* storage world.
*/
public static final ResourceLocation CHUNK_GENERATOR_ID = AppEng.makeId("spatial_storage");
/**
* ID of the {@link net.minecraft.world.biome.Biome} used for the spatial
* storage world.
*/
public static final ResourceLocation BIOME_ID = AppEng.makeId("spatial_storage");
/**
* ID of the {@link Dimension} used for the spatial storage dimension.
* <p>
* This is defined in
* <code>data/minecraft/dimension/appliedenergistics2/spatial_storage.json</code>
*/
public static final RegistryKey<Dimension> DIMENSION_ID = RegistryKey.func_240903_a_(Registry.DIMENSION_KEY,
AppEng.makeId("spatial_storage"));
/**
* ID of the {@link World} that is instantiated from the dimension/dimension
* type.
*/
public static final RegistryKey<World> WORLD_ID = RegistryKey.func_240903_a_(Registry.WORLD_KEY,
AppEng.makeId("spatial_storage"));
private SpatialStorageDimensionIds() {
}
}
@@ -39,13 +39,13 @@ import appeng.api.util.WorldCoord;
import appeng.core.Api;
import appeng.core.AppEng;
public class StorageHelper {
public class SpatialStorageHelper {
private static StorageHelper instance;
private static SpatialStorageHelper instance;
public static StorageHelper getInstance() {
public static SpatialStorageHelper getInstance() {
if (instance == null) {
instance = new StorageHelper();
instance = new SpatialStorageHelper();
}
return instance;
}
@@ -64,7 +64,7 @@ public class StorageHelper {
try {
oldWorld = (ServerWorld) entity.world;
newWorld = (ServerWorld) link.dim;
newWorld = link.dim;
} catch (final Throwable e) {
return entity;
}
@@ -98,7 +98,7 @@ public class StorageHelper {
ChunkStatus.FULL, true);
if (entity instanceof ServerPlayerEntity
&& link.dim.func_234922_V_() == SpatialDimensionManager.STORAGE_DIMENSION_TYPE) {
&& link.dim.func_234922_V_() == SpatialStorageDimensionIds.DIMENSION_TYPE_ID) {
AppEng.instance().getAdvancementTriggers().getSpatialExplorer().trigger((ServerPlayerEntity) entity);
}
@@ -0,0 +1,189 @@
package appeng.spatial;
import java.util.Locale;
import javax.annotation.Nullable;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraftforge.common.util.Constants;
/**
* A plot inside the storage cell world that is assigned to a specific storage
* cell.
*/
public class SpatialStoragePlot {
private static final String TAG_ID = "id";
private static final String TAG_SIZE = "size";
private static final String TAG_OWNER = "owner";
private static final String TAG_LAST_TRANSITION = "last_transition";
private static final int REGION_SIZE = 512;
public static final int MAX_SIZE = 128;
/**
* Id of the plot.
*/
private final int id;
/**
* The storage size of this dimension. This is dictated by the pylon structure
* size used to perform the first transfer into this dimension. Once it's set,
* it cannot be changed anymore.
*/
private final BlockPos size;
/**
* AE2 player id of who primarily owned the network when the storage plot was
* allocated.
*/
private final int owner;
/**
* Information about the last transition into this plot.
*/
@Nullable
private TransitionInfo lastTransition;
public SpatialStoragePlot(int id, BlockPos size, int owner) {
this.id = id;
this.size = size;
this.owner = owner;
if (size.getX() < 1 || size.getY() < 1 || size.getZ() < 1) {
throw new IllegalArgumentException("Plot size " + size + " is smaller than minimum size.");
}
if (size.getX() > MAX_SIZE || size.getY() > MAX_SIZE || size.getZ() > MAX_SIZE) {
throw new IllegalArgumentException("Plot size " + size + " exceeds maximum size of " + MAX_SIZE);
}
}
public int getId() {
return id;
}
/**
* The size in blocks of the plot in the storage dimension.
*
* @see #getOrigin()
*/
public BlockPos getSize() {
return size;
}
/**
* Returns the AE player id of the owner of this plot, or -1 if unknown.
*
* @see appeng.core.worlddata.IWorldPlayerData
*/
public int getOwner() {
return owner;
}
/**
* Returns information about the last transition into this plot (if any).
*/
@Nullable
public TransitionInfo getLastTransition() {
return lastTransition;
}
void setLastTransition(TransitionInfo info) {
this.lastTransition = info;
}
/**
* The origin of this plot within the spatial storage dimension.
* <p>
* To map an integer to a specific position, it uses the following algorithm.
*
* The 2 least significant bits determine the sign for the x and z axis. Every
* other pack of 2 bits locate the plot within a quadrant of a increasing area
* by the bit position.
*
* The first 2 bits after the sign address a quadrant within 1024x1024 blocks
* (or 4 region files)
*
* Every further will continue to double both x and z values. E.g. 2048x2048 for
* the 3rd pack and 4096x4096 for the 4th.
*
* @see #getSize()
*/
public BlockPos getOrigin() {
int signBits = id & 0b11;
int offsetBits = id >> 2;
int offsetScale = 1;
int posx = REGION_SIZE / 2;
int posz = REGION_SIZE / 2;
// find quadrant
while (offsetBits != 0) {
posx += REGION_SIZE * offsetScale * (offsetBits & 0b01);
posz += REGION_SIZE * offsetScale * (offsetBits >> 1 & 0b01);
offsetBits >>= 2;
offsetScale <<= 1;
}
// mirror in one of 4 directions
// First flip the z axis on every increment and then every two the x axis
if ((signBits & 0b01) != 0) {
posz *= -1;
}
if ((signBits & 0b10) != 0) {
posx *= -1;
}
// offset from cell center
//
// This is to ensure a 128x128x128 block plot (or 8x8 chunks) is centered within
// the region.
// This provides 12 chunks around it, so the default chunk loading radius on
// servers of 10 will prevent adjacent regions to be generated. As well as a 24
// chunks to the next plot.
posx -= 64;
posz -= 64;
return new BlockPos(posx, 64, posz);
}
/**
* Returns the filename of the region in the world save containing this plot.
*/
public String getRegionFilename() {
BlockPos origin = this.getOrigin();
ChunkPos originChunk = new ChunkPos(origin);
return String.format(Locale.ROOT, "r.%d.%d.mca", originChunk.getRegionCoordX(), originChunk.getRegionCoordZ());
}
public CompoundNBT toTag() {
CompoundNBT tag = new CompoundNBT();
tag.putInt(TAG_ID, id);
tag.put(TAG_SIZE, NBTUtil.writeBlockPos(size));
tag.putInt(TAG_OWNER, owner);
if (lastTransition != null) {
tag.put(TAG_LAST_TRANSITION, lastTransition.toTag());
}
return tag;
}
public static SpatialStoragePlot fromTag(CompoundNBT tag) {
int id = tag.getInt(TAG_ID);
BlockPos size = NBTUtil.readBlockPos(tag.getCompound(TAG_SIZE));
int ownerId = tag.getInt(TAG_OWNER);
SpatialStoragePlot plot = new SpatialStoragePlot(id, size, ownerId);
if (tag.contains(TAG_LAST_TRANSITION, Constants.NBT.TAG_COMPOUND)) {
plot.lastTransition = TransitionInfo.fromTag(tag.getCompound(TAG_LAST_TRANSITION));
}
return plot;
}
}
@@ -0,0 +1,118 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2017, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 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.
*
* Applied Energistics 2 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 Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import appeng.core.AELog;
import appeng.core.Api;
/**
* Allocates and manages plots for spatial storage in the spatial storage world.
*/
public final class SpatialStoragePlotManager {
public static final SpatialStoragePlotManager INSTANCE = new SpatialStoragePlotManager();
private SpatialStoragePlotManager() {
}
/**
* Gets the world used to store spatial storage cell's content.
*/
public ServerWorld getWorld() {
MinecraftServer server = getServer();
ServerWorld world = server.getWorld(SpatialStorageDimensionIds.WORLD_ID);
if (world == null) {
throw new IllegalStateException("The storage cell world is missing.");
}
return world;
}
private SpatialStorageWorldData getWorldData() {
return getWorld().getChunkProvider().getSavedData().getOrCreate(SpatialStorageWorldData::new,
SpatialStorageWorldData.ID);
}
@Nullable
public SpatialStoragePlot getPlot(int plotId) {
if (plotId == -1) {
return null;
}
return getWorldData().getPlotById(plotId);
}
public SpatialStoragePlot allocatePlot(BlockPos size, int ownerId) {
SpatialStoragePlot plot = getWorldData().allocatePlot(size, ownerId);
AELog.info("Allocating storage cell plot %d with size %s for %d", plot.getId(), size, ownerId);
return plot;
}
/**
* Sets the last source for a spatial storage transition into the given plot.
* This is used to allow the server-admin commands to know where the content of
* a given plot came from.
*/
public void setLastTransition(int plotId, TransitionInfo info) {
getWorldData().setLastTransition(plotId, info);
}
/**
* Returns an immutable list of all plots.
*/
public List<SpatialStoragePlot> getPlots() {
return getWorldData().getPlots();
}
public void freePlot(int plotId, boolean resetBlocks) {
SpatialStoragePlot plot = getPlot(plotId);
if (plot == null) {
return; // Already removed apparently
}
if (resetBlocks) {
BlockPos from = plot.getOrigin();
BlockPos to = from.add(plot.getSize()).add(-1, -1, -1);
AELog.info("Clearing spatial storage plot %s (%s -> %s)", plotId, from, to);
// This is slow, but it should usually be just an admin-command
ServerWorld world = getWorld();
BlockState matrixFrame = Api.instance().definitions().blocks().matrixFrame().block().getDefaultState();
for (BlockPos blockPos : BlockPos.getAllInBoxMutable(from, to)) {
world.setBlockState(blockPos, matrixFrame);
}
}
getWorldData().removePlot(plotId);
}
private static MinecraftServer getServer() {
return ServerLifecycleHooks.getCurrentServer();
}
}
@@ -7,8 +7,11 @@ import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
/**
* Defines properties for how the sky in the spatial storage world is rendered.
*/
@OnlyIn(Dist.CLIENT)
public class StorageSkyProperties {
public class SpatialStorageSkyProperties {
// See the fabric version of this to get any idea what its doing
public static final DimensionRenderInfo INSTANCE = new DimensionRenderInfo(Float.NaN /* disables clouds */, false,
@@ -0,0 +1,110 @@
package appeng.spatial;
import java.util.List;
import com.google.common.collect.ImmutableList;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.storage.WorldSavedData;
import net.minecraftforge.common.util.Constants;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import appeng.core.AELog;
/**
* Extra data attached to the spatial storage world.
*/
public class SpatialStorageWorldData extends WorldSavedData {
/**
* ID of this data when it is attached to a world.
*/
public static final String ID = "ae2_spatial_storage";
// Used to allow forward compatibility
private static final int CURRENT_FORMAT = 2;
private static final String TAG_FORMAT = "format";
private static final String TAG_PLOTS = "plots";
private final Int2ObjectOpenHashMap<SpatialStoragePlot> plots = new Int2ObjectOpenHashMap<>();
public SpatialStorageWorldData() {
super(ID);
}
public SpatialStoragePlot getPlotById(int id) {
return plots.get(id);
}
public List<SpatialStoragePlot> getPlots() {
return ImmutableList.copyOf(plots.values());
}
public SpatialStoragePlot allocatePlot(BlockPos size, int owner) {
int nextId = 1;
for (int id : plots.keySet()) {
if (id >= nextId) {
nextId = id + 1;
}
}
SpatialStoragePlot plot = new SpatialStoragePlot(nextId, size, owner);
plots.put(nextId, plot);
markDirty();
return plot;
}
public void removePlot(int plotId) {
plots.remove(plotId);
markDirty();
}
public void setLastTransition(int plotId, TransitionInfo info) {
SpatialStoragePlot plot = plots.get(plotId);
if (plot != null) {
plot.setLastTransition(info);
}
markDirty();
}
@Override
public void read(CompoundNBT tag) {
int version = tag.getInt(TAG_FORMAT);
if (version != CURRENT_FORMAT) {
// Currently no new format has been defined, as such anything but the current
// version is invalid
throw new IllegalStateException("Invalid AE2 spatial info version: " + version);
}
ListNBT plotsTag = tag.getList(TAG_PLOTS, Constants.NBT.TAG_COMPOUND);
for (INBT plotTag : plotsTag) {
SpatialStoragePlot plot = SpatialStoragePlot.fromTag((CompoundNBT) plotTag);
if (plots.containsKey(plot.getId())) {
AELog.warn("Overwriting duplicate plot id %s", plot.getId());
}
plots.put(plot.getId(), plot);
}
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putInt(TAG_FORMAT, CURRENT_FORMAT);
ListNBT plotTags = new ListNBT();
for (SpatialStoragePlot plot : plots.values()) {
plotTags.add(plot.toTag());
}
tag.put(TAG_PLOTS, plotTags);
return tag;
}
}
@@ -0,0 +1,69 @@
package appeng.spatial;
import java.time.Instant;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
/**
* Defines the source world and area of a transition into the spatial storage
* plot.
*/
public final class TransitionInfo {
public static final String TAG_WORLD_ID = "world_id";
public static final String TAG_MIN = "min";
public static final String TAG_MAX = "max";
public static final String TAG_TIMESTAMP = "timestamp";
private final ResourceLocation worldId;
private final BlockPos min;
private final BlockPos max;
private final Instant timestamp;
public TransitionInfo(ResourceLocation worldId, BlockPos min, BlockPos max, Instant timestamp) {
this.worldId = worldId;
this.min = min.toImmutable();
this.max = max.toImmutable();
this.timestamp = timestamp;
}
public ResourceLocation getWorldId() {
return worldId;
}
public BlockPos getMin() {
return min;
}
public BlockPos getMax() {
return max;
}
public Instant getTimestamp() {
return timestamp;
}
public CompoundNBT toTag() {
CompoundNBT tag = new CompoundNBT();
tag.putString(TAG_WORLD_ID, worldId.toString());
tag.put(TAG_MIN, NBTUtil.writeBlockPos(min));
tag.put(TAG_MAX, NBTUtil.writeBlockPos(max));
tag.putLong(TAG_TIMESTAMP, timestamp.toEpochMilli());
return tag;
}
public static TransitionInfo fromTag(CompoundNBT tag) {
ResourceLocation worldId = new ResourceLocation(tag.getString(TAG_WORLD_ID));
BlockPos min = NBTUtil.readBlockPos(tag.getCompound(TAG_MIN));
BlockPos max = NBTUtil.readBlockPos(tag.getCompound(TAG_MAX));
Instant timestamp = Instant.ofEpochMilli(tag.getLong(TAG_TIMESTAMP));
return new TransitionInfo(worldId, min, max, timestamp);
}
}
@@ -304,6 +304,7 @@ public class AEBaseTileEntity extends TileEntity implements IOrientable, ICommon
this.up = inUp;
this.markForUpdate();
Platform.notifyBlocksOfNeighbors(this.world, this.pos);
this.saveChanges();
}
public void onPlacement(BlockItemUseContext context) {
@@ -80,6 +80,10 @@ public abstract class AENetworkInvTileEntity extends AEBaseInvTileEntity impleme
@Override
public void remove() {
super.remove();
// if the cached block state is not current, the following method may call
// markForUpdate
// and cause the block state to be changed back to non-air
updateContainingBlockInfo();
this.getProxy().remove();
}
@@ -32,7 +32,6 @@ import net.minecraftforge.items.IItemHandler;
import appeng.api.config.Actionable;
import appeng.api.config.PowerMultiplier;
import appeng.api.config.YesNo;
import appeng.api.implementations.TransitionResult;
import appeng.api.implementations.items.ISpatialStorageCell;
import appeng.api.networking.GridFlags;
import appeng.api.networking.IGrid;
@@ -135,14 +134,18 @@ public class SpatialIOPortTileEntity extends AENetworkInvTileEntity implements I
if (Math.abs(pr - req) < req * 0.001) {
final MENetworkEvent res = gi.postEvent(new MENetworkSpatialEvent(this, req));
if (!res.isCanceled()) {
int playerId = -1;
// Prefer player id from security system, but if unavailable, use the
// player who placed the grid node (if any)
int playerId;
if (this.getProxy().getSecurity().isAvailable()) {
playerId = this.getProxy().getSecurity().getOwner();
} else {
playerId = this.getProxy().getNode().getPlayerID();
}
final TransitionResult tr = sc.doSpatialTransition(cell, serverWorld, spc.getMin(),
spc.getMax(), playerId);
if (tr.success) {
boolean success = sc.doSpatialTransition(cell, serverWorld, spc.getMin(), spc.getMax(),
playerId);
if (success) {
energy.extractAEPower(req, Actionable.MODULATE, PowerMultiplier.CONFIG);
this.inv.setStackInSlot(0, ItemStack.EMPTY);
this.inv.setStackInSlot(1, cell);
@@ -38,6 +38,12 @@ public class MeteoriteStructurePiece extends StructurePiece {
public static final IStructurePieceType TYPE = IStructurePieceType.register(MeteoriteStructurePiece::new,
"AE2MTRT");
public static void register() {
// THIS MUST BE CALLED otherwise the static initializer above will not run,
// unless world generation is actually invoked, which means that chunks may
// be loaded without this being registered as a structure piece!
}
private PlacedMeteoriteSettings settings;
protected MeteoriteStructurePiece(BlockPos center, float coreRadius, CraterType craterType, FalloutMode fallout,
+1 -1
View File
@@ -16,7 +16,7 @@ description="A Mod about Matter, Energy and using them to conquer the world.."
[[dependencies.appliedenergistics2]]
modId="forge"
mandatory=true
versionRange="[32.0.75,33.0.0)"
versionRange="[32.0.108,33.0.0)"
ordering="NONE"
side="BOTH"
@@ -5,13 +5,20 @@
"refmap": "appliedenergistics2.mixins.refmap.json",
"compatibilityLevel": "JAVA_8",
"mixins": [
"DimensionTypeMixin",
"MinecraftServerMixin",
"spatial.DimensionTypeMixin",
"spatial.DimensionOptionMixin",
"ThreadedAnvilChunkStorageAccessor",
"DimensionStructuresSettingsMixin",
"StructureAccessor"
],
"client": ["SkyRenderMixin", "SkyPropertiesMixin"],
"client": [
"spatial.SkyRenderMixin",
"spatial.SkyPropertiesMixin",
"unlitquad.ModelBakeryMixin",
"unlitquad.BlockModelMixin",
"unlitquad.BlockPartFaceDeserializerMixin",
"unlitquad.BakedQuadAccessor"
],
"server": [],
"injectors": {
"defaultRequire": 1
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"parent": "block/block",
"textures": {
"block": "block/stone",
@@ -42,50 +41,32 @@
"down": {
"texture": "#quartz",
"cullface": "down",
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"east": {
"texture": "#quartz",
"cullface": "east",
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"north": {
"texture": "#quartz",
"cullface": "north",
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"south": {
"texture": "#quartz",
"cullface": "south",
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"up": {
"texture": "#quartz",
"cullface": "up",
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"west": {
"texture": "#quartz",
"cullface": "west",
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
},
"from": [0, 0, 0],
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"lights_bright": "appliedenergistics2:block/chest/lights_on_bright",
"lights_medium": "appliedenergistics2:block/chest/lights_on_medium",
@@ -13,10 +12,7 @@
"up": {
"texture": "#lights_bright",
"tintindex": 3,
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
}
},
@@ -27,10 +23,7 @@
"up": {
"texture": "#lights_medium",
"tintindex": 2,
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
}
},
@@ -41,10 +34,7 @@
"up": {
"texture": "#lights_dark",
"tintindex": 1,
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"parent": "block/block",
"textures": {
"block": "appliedenergistics2:block/controller_powered",
@@ -12,50 +11,32 @@
"down": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"east": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"north": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"south": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"up": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"west": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
},
"from": [0, 0, 0],
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"parent": "block/block",
"textures": {
"block": "appliedenergistics2:block/controller_powered",
@@ -12,50 +11,32 @@
"down": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"east": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"north": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"south": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"up": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"west": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
},
"from": [0, 0, 0],
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"parent": "block/block",
"textures": {
"block": "appliedenergistics2:block/controller_column_powered",
@@ -12,50 +11,32 @@
"down": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"east": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"north": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"south": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"up": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"west": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
},
"from": [0, 0, 0],
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"parent": "block/block",
"textures": {
"block": "appliedenergistics2:block/controller_column_powered",
@@ -12,50 +11,32 @@
"down": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"east": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"north": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"south": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"up": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
},
"west": {
"texture": "#lights",
"uv": [0, 0, 16, 16],
"uvlightmap": {
"block": 0.007,
"sky": 0.007
}
"unlit": true
}
},
"from": [0, 0, 0],
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"parent": "block/block",
"textures": {
"all": "appliedenergistics2:block/molecular_assembler_lights"
@@ -13,55 +12,37 @@
"texture": "#all",
"uv": [2.6, 2.6, 13.4, 13.4],
"cullface": "down",
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#all",
"uv": [2.6, 2.6, 13.4, 13.4],
"cullface": "up",
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"north": {
"texture": "#all",
"uv": [2.6, 2.6, 13.4, 13.4],
"cullface": "north",
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"south": {
"texture": "#all",
"uv": [2.6, 2.6, 13.4, 13.4],
"cullface": "south",
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#all",
"uv": [2.6, 2.6, 13.4, 13.4],
"cullface": "west",
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#all",
"uv": [2.6, 2.6, 13.4, 13.4],
"cullface": "east",
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"parent": "block/block",
"textures": {
"particle": "appliedenergistics2:block/security_station_side",
@@ -42,10 +41,7 @@
"up": {
"texture": "#lightsBright",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -56,10 +52,7 @@
"up": {
"texture": "#lightsMedium",
"tintindex": 2,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -70,10 +63,7 @@
"up": {
"texture": "#lightsDark",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"ambientocclusion": false,
"textures": {
"torch": "appliedenergistics2:block/wireless_access_point_on"
@@ -39,10 +38,7 @@
"texture": "#torch",
"uv": [7, 7, 9, 9],
"rotation": 270,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -55,19 +51,13 @@
"texture": "#torch",
"uv": [6, 6, 10, 10],
"rotation": 90,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"down": {
"texture": "#torch",
"uv": [6, 6, 10, 10],
"rotation": 270,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -79,19 +69,13 @@
"west": {
"texture": "#torch",
"uv": [6, 6, 10, 10],
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#torch",
"uv": [6, 6, 10, 10],
"rotation": 180,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -10,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -10,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"lightsBright": "appliedenergistics2:part/conversion_monitor_bright",
"lightsMedium": "appliedenergistics2:part/conversion_monitor_medium_locked",
@@ -13,10 +12,7 @@
"north": {
"texture": "#lightsBright",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -27,10 +23,7 @@
"north": {
"texture": "#lightsMedium",
"tintindex": 2,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -41,10 +34,7 @@
"north": {
"texture": "#lightsDark",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"lightsBright": "appliedenergistics2:part/conversion_monitor_bright",
"lightsMedium": "appliedenergistics2:part/conversion_monitor_medium",
@@ -13,10 +12,7 @@
"north": {
"texture": "#lightsBright",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -27,10 +23,7 @@
"north": {
"texture": "#lightsMedium",
"tintindex": 2,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -41,10 +34,7 @@
"north": {
"texture": "#lightsDark",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"lightsBright": "appliedenergistics2:part/crafting_terminal_bright",
"lightsMedium": "appliedenergistics2:part/crafting_terminal_medium",
@@ -13,10 +12,7 @@
"north": {
"texture": "#lightsBright",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -27,10 +23,7 @@
"north": {
"texture": "#lightsMedium",
"tintindex": 2,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
},
@@ -41,10 +34,7 @@
"north": {
"texture": "#lightsDark",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"indicator": "appliedenergistics2:part/monitor_sides_status_has_channel"
},
@@ -11,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"indicator": "appliedenergistics2:part/monitor_sides_status_on"
},
@@ -11,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"indicator": "appliedenergistics2:part/monitor_sides_status_has_channel"
},
@@ -11,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"indicator": "appliedenergistics2:part/monitor_sides_status_on"
},
@@ -11,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"indicator": "appliedenergistics2:part/monitor_sides_status_has_channel"
},
@@ -11,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 1,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}
@@ -1,5 +1,4 @@
{
"loader": "appliedenergistics2:uvlightmap",
"textures": {
"indicator": "appliedenergistics2:part/monitor_sides_status_on"
},
@@ -11,34 +10,22 @@
"down": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"up": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"east": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
},
"west": {
"texture": "#indicator",
"tintindex": 3,
"uvlightmap": {
"sky": 0.007,
"block": 0.007
}
"unlit": true
}
}
}

Some files were not shown because too many files have changed in this diff Show More