Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d07937fa93 | |||
| 65f58913a4 | |||
| 81cc0b804d | |||
| e1fc9908b3 | |||
| 9ed1535477 | |||
| 1ef345d4a4 | |||
| ff7d1b9719 | |||
| 88c9370e4f | |||
| f2aae3ef0f | |||
| 12739f1e66 | |||
| 81d2170ada | |||
| 0f34f09b32 | |||
| 8e54a8fed9 | |||
| d9bb81a00f | |||
| 39e038d916 | |||
| f0d0595c8f | |||
| 7c99fca789 | |||
| ab393b0ed1 | |||
| 133ed1f09d | |||
| db9ec2b070 | |||
| 00d4c20d9f | |||
| 5efc085693 | |||
| aff94cec8c | |||
| 2184d03d0b | |||
| 44c0931c02 | |||
| 423ab81813 | |||
| 4e42b17e81 | |||
| fc0f8eab56 | |||
| 41b7900706 | |||
| 7656157b0d | |||
| 87c2c94bd4 | |||
| d591a1492c | |||
| d1ba26311b | |||
| 8733c2c11f | |||
| 4230fc7325 | |||
| 484af8baf3 | |||
| 9456f639d4 | |||
| fe753c540b | |||
| 2fabab3a6a | |||
| 6f39bd8fe8 | |||
| c7d3877129 |
@@ -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: |
|
||||
|
||||
@@ -190,6 +190,13 @@ publishing {
|
||||
groupId = project.group
|
||||
artifactId = project.archivesBaseName
|
||||
version = project.version
|
||||
|
||||
// ForgeGradle will generate wild dependency definitions, see https://github.com/MinecraftForge/ForgeGradle/issues/584
|
||||
// Since we don't actually depend on anything, just remove the entire node.
|
||||
pom.withXml {
|
||||
asNode().remove(asNode().dependencies)
|
||||
}
|
||||
|
||||
from components.java
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
@@ -205,5 +212,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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -23,13 +23,23 @@
|
||||
|
||||
package appeng.api.implementations.items;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IGrowableCrystal {
|
||||
|
||||
ItemStack triggerGrowth(ItemStack is);
|
||||
|
||||
float getMultiplier(Block blk, Material mat);
|
||||
/**
|
||||
* Gets the crystal growth multiplier based on the material it is submerged in.
|
||||
*
|
||||
* @param state The blockstate of the block the crystal is currently in.
|
||||
* @return The multiplier for the growth tick progress. Zero if the crystal
|
||||
* cannot grow in the current material.
|
||||
*/
|
||||
float getMultiplier(BlockState state, @Nullable World world, @Nullable BlockPos pos);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -28,4 +28,9 @@ public enum GridNotification {
|
||||
* the visible connections for this node have changed, useful for cable.
|
||||
*/
|
||||
CONNECTIONS_CHANGED,
|
||||
|
||||
/**
|
||||
* the owner of the grid node has changed, and the node needs to be re-saved
|
||||
*/
|
||||
OWNER_CHANGED
|
||||
}
|
||||
|
||||
@@ -87,7 +87,8 @@ public interface IGridBlock {
|
||||
AEColor getGridColor();
|
||||
|
||||
/**
|
||||
* Notifies your IGridBlock that changes were made to your connections
|
||||
* Called by the {@link IGridNode} to notify its {@link IGridBlock} about
|
||||
* events.
|
||||
*/
|
||||
void onGridNotification(@Nonnull GridNotification notification);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -39,6 +39,8 @@ import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.DyeColor;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.state.IntegerProperty;
|
||||
import net.minecraft.state.StateContainer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
@@ -82,8 +84,12 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusTileEntity> implement
|
||||
|
||||
private static final ICableBusContainer NULL_CABLE_BUS = new NullCableBusContainer();
|
||||
|
||||
private static final IntegerProperty LIGHT_LEVEL = IntegerProperty.create("light_level", 0, 15);
|
||||
|
||||
public CableBusBlock() {
|
||||
super(defaultProps(AEMaterials.GLASS).notSolid().noDrops().variableOpacity());
|
||||
super(defaultProps(AEMaterials.GLASS).notSolid().noDrops().variableOpacity()
|
||||
.setLightLevel(state -> state.get(LIGHT_LEVEL)));
|
||||
setDefaultState(getDefaultState().with(LIGHT_LEVEL, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,11 +132,9 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusTileEntity> implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue(final BlockState state, final IBlockReader world, final BlockPos pos) {
|
||||
if (state.getBlock() != this) {
|
||||
return state.getBlock().getLightValue(state, world, pos);
|
||||
}
|
||||
return this.cb(world, pos).getLightValue();
|
||||
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
|
||||
super.fillStateContainer(builder);
|
||||
builder.add(LIGHT_LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -386,4 +390,13 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusTileEntity> implement
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState updateBlockStateFromTileEntity(BlockState currentState, CableBusTileEntity te) {
|
||||
if (currentState.getBlock() != this) {
|
||||
return currentState;
|
||||
}
|
||||
int lightLevel = te.getCableBus().getLightValue();
|
||||
return super.updateBlockStateFromTileEntity(currentState, te).with(LIGHT_LEVEL, lightLevel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -8,19 +8,18 @@ import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
|
||||
/**
|
||||
* A proxy for a slot that will always return an itemstack with size 1, if there
|
||||
* is an item in the slot. Used to prevent the default item count from
|
||||
* rendering.
|
||||
*/
|
||||
class Size1Slot extends SlotItemHandler {
|
||||
class Size1Slot extends Slot {
|
||||
|
||||
private final SlotItemHandler delegate;
|
||||
private final Slot delegate;
|
||||
|
||||
public Size1Slot(SlotItemHandler delegate) {
|
||||
super(delegate.getItemHandler(), delegate.getSlotIndex(), delegate.xPos, delegate.yPos);
|
||||
public Size1Slot(Slot delegate) {
|
||||
super(delegate.inventory, delegate.getSlotIndex(), delegate.xPos, delegate.yPos);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,11 +41,6 @@ import appeng.fluids.util.FluidSorters;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.prioritylist.IPartitionList;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class FluidRepo {
|
||||
private final IItemList<IAEFluidStack> list = Api.instance().storage().getStorageChannel(IFluidStorageChannel.class)
|
||||
.createList();
|
||||
|
||||
@@ -21,23 +21,22 @@ package appeng.client.me;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.fluids.container.slots.IMEFluidSlot;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
public class SlotFluidME extends Slot implements IMEFluidSlot {
|
||||
|
||||
private InternalFluidSlotME slot;
|
||||
private static final IInventory EMPTY_INVENTORY = new Inventory(0);
|
||||
|
||||
private final InternalFluidSlotME slot;
|
||||
|
||||
public SlotFluidME(InternalFluidSlotME slot) {
|
||||
super(null, 0, slot.getxPosition(), slot.getyPosition());
|
||||
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
@@ -50,7 +49,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(final ItemStack par1ItemStack) {
|
||||
public boolean isItemValid(final ItemStack stack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -69,7 +68,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putStack(final ItemStack par1ItemStack) {
|
||||
public void putStack(final ItemStack stack) {
|
||||
|
||||
}
|
||||
|
||||
@@ -85,7 +84,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeStack(final PlayerEntity par1PlayerEntity) {
|
||||
public boolean canTakeStack(final PlayerEntity player) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,23 +19,27 @@
|
||||
package appeng.client.me;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
|
||||
public class SlotME extends SlotItemHandler {
|
||||
public class SlotME extends Slot {
|
||||
|
||||
private final InternalSlotME mySlot;
|
||||
private static final IInventory EMPTY_INVENTORY = new Inventory(0);
|
||||
|
||||
public SlotME(final InternalSlotME me) {
|
||||
super(null, 0, me.getxPosition(), me.getyPosition());
|
||||
this.mySlot = me;
|
||||
private final InternalSlotME slot;
|
||||
|
||||
public SlotME(final InternalSlotME slot) {
|
||||
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
public IAEItemStack getAEStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
return this.mySlot.getAEStack();
|
||||
if (this.slot.hasPower()) {
|
||||
return this.slot.getAEStack();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -47,15 +51,15 @@ public class SlotME extends SlotItemHandler {
|
||||
|
||||
@Override
|
||||
public ItemStack getStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
return this.mySlot.getStack();
|
||||
if (this.slot.hasPower()) {
|
||||
return this.slot.getStack();
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getHasStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
if (this.slot.hasPower()) {
|
||||
return !this.getStack().isEmpty();
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,6 @@ package appeng.client.render.cablebus;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -30,6 +29,11 @@ import java.util.Random;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.cache.Weigher;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
@@ -50,7 +54,10 @@ import appeng.api.util.AEColor;
|
||||
|
||||
public class CableBusBakedModel implements IBakedModel {
|
||||
|
||||
private static final Map<CableBusRenderState, List<BakedQuad>> CABLE_MODEL_CACHE = new HashMap<>();
|
||||
// The number of quads overall that will be cached
|
||||
private static final int CACHE_QUAD_COUNT = 5000;
|
||||
|
||||
private final LoadingCache<CableBusRenderState, List<BakedQuad>> cableModelCache;
|
||||
|
||||
private final CableBuilder cableBuilder;
|
||||
|
||||
@@ -66,6 +73,17 @@ public class CableBusBakedModel implements IBakedModel {
|
||||
this.facadeBuilder = facadeBuilder;
|
||||
this.partModels = partModels;
|
||||
this.particleTexture = particleTexture;
|
||||
this.cableModelCache = CacheBuilder.newBuilder()//
|
||||
.maximumWeight(CACHE_QUAD_COUNT)//
|
||||
.weigher((Weigher<CableBusRenderState, List<BakedQuad>>) (key, value) -> value.size())//
|
||||
.build(new CacheLoader<CableBusRenderState, List<BakedQuad>>() {
|
||||
@Override
|
||||
public List<BakedQuad> load(CableBusRenderState renderState) {
|
||||
final List<BakedQuad> model = new ArrayList<>();
|
||||
addCableQuads(renderState, model);
|
||||
return model;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,11 +110,7 @@ public class CableBusBakedModel implements IBakedModel {
|
||||
if (layer == RenderType.getCutout()) {
|
||||
|
||||
// First, handle the cable at the center of the cable bus
|
||||
final List<BakedQuad> cableModel = CABLE_MODEL_CACHE.computeIfAbsent(renderState, k -> {
|
||||
final List<BakedQuad> model = new ArrayList<>();
|
||||
this.addCableQuads(renderState, model);
|
||||
return model;
|
||||
});
|
||||
final List<BakedQuad> cableModel = cableModelCache.getUnchecked(renderState);
|
||||
quads.addAll(cableModel);
|
||||
|
||||
// Then handle attachments
|
||||
@@ -341,8 +355,4 @@ public class CableBusBakedModel implements IBakedModel {
|
||||
return ItemOverrideList.EMPTY;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
CABLE_MODEL_CACHE.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class CableBusModelLoader implements IModelLoader<CableBusModel> {
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {
|
||||
CableBusBakedModel.clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import appeng.api.networking.security.IActionHost;
|
||||
import appeng.container.AEBaseContainer;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.CompressedNBTPacket;
|
||||
import appeng.core.sync.packets.MEInterfaceUpdatePacket;
|
||||
import appeng.helpers.DualityInterface;
|
||||
import appeng.helpers.IInterfaceHost;
|
||||
import appeng.helpers.InventoryAction;
|
||||
@@ -177,7 +177,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
|
||||
if (!this.data.isEmpty()) {
|
||||
try {
|
||||
NetworkHandler.instance().sendTo(new CompressedNBTPacket(this.data),
|
||||
NetworkHandler.instance().sendTo(new MEInterfaceUpdatePacket(this.data),
|
||||
(ServerPlayerEntity) this.getPlayerInv().player);
|
||||
} catch (final IOException e) {
|
||||
// :P
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.util.Set;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -393,6 +395,15 @@ public final class AEConfig {
|
||||
return this.meteoriteDimensionWhitelist;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getImprovedFluidTag() {
|
||||
return Strings.emptyToNull(COMMON.improvedFluidTag.get());
|
||||
}
|
||||
|
||||
public float getImprovedFluidMultiplier() {
|
||||
return COMMON.improvedFluidMultiplier.get().floatValue();
|
||||
}
|
||||
|
||||
// Setters keep visibility as low as possible.
|
||||
|
||||
private static class ClientConfig {
|
||||
@@ -507,6 +518,11 @@ public final class AEConfig {
|
||||
public final ConfigValue<Integer> condenserMatterBallsPower;
|
||||
public final ConfigValue<Integer> condenserSingularityPower;
|
||||
|
||||
// In-World Purification
|
||||
// Settings for improved speed depending on fluid the crystal is in
|
||||
public final ConfigValue<String> improvedFluidTag;
|
||||
public final ConfigValue<Double> improvedFluidMultiplier;
|
||||
|
||||
public final Map<TickRates, ConfigValue<Integer>> tickRateMin = new HashMap<>();
|
||||
public final Map<TickRates, ConfigValue<Integer>> tickRateMax = new HashMap<>();
|
||||
|
||||
@@ -617,6 +633,17 @@ public final class AEConfig {
|
||||
tickRateMax.put(tickRate, builder.define(tickRate.name() + "Max", tickRate.getDefaultMax()));
|
||||
}
|
||||
builder.pop();
|
||||
|
||||
builder.comment("Settings for in-world purification of crystals.").push("inWorldPurification");
|
||||
|
||||
improvedFluidTag = builder.comment(
|
||||
"A fluid tag that identifies fluids that improve crystal purification speed. Does not affect purification with water/lava.")
|
||||
.define("improvedFluidTag", "");
|
||||
improvedFluidMultiplier = builder
|
||||
.comment("The speed multiplier to use when the crystals are submerged in the improved fluid.")
|
||||
.defineInRange("improvedFluidMultiplier", 2.0, 1.0, 10.0);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -20,7 +20,9 @@ package appeng.core.api.definitions;
|
||||
|
||||
import static appeng.block.AEBaseBlock.defaultProps;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.DispenserBlock;
|
||||
import net.minecraft.block.SlabBlock;
|
||||
import net.minecraft.block.SoundType;
|
||||
@@ -28,6 +30,7 @@ import net.minecraft.block.StairsBlock;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.entity.EntityClassification;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
@@ -262,18 +265,20 @@ public final class ApiBlocks implements IBlocks {
|
||||
this.chiseledQuartzBlock = deco.block("chiseled_quartz_block", () -> new AEDecorativeBlock(QUARTZ_PROPERTIES))
|
||||
.build();
|
||||
|
||||
this.quartzGlass = registry.features(AEFeature.QUARTZ_GLASS)
|
||||
.block("quartz_glass", () -> new QuartzGlassBlock(defaultProps(Material.GLASS).notSolid()))
|
||||
.rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
rendering.renderType(RenderType.getCutout());
|
||||
}
|
||||
}).build();
|
||||
AbstractBlock.IExtendedPositionPredicate<EntityType<?>> neverAllowSpawn = (p1, p2, p3, p4) -> false;
|
||||
this.quartzGlass = registry.features(AEFeature.QUARTZ_GLASS).block("quartz_glass", () -> {
|
||||
return new QuartzGlassBlock(defaultProps(Material.GLASS).notSolid().setAllowsSpawn(neverAllowSpawn));
|
||||
}).rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
rendering.renderType(RenderType.getCutout());
|
||||
}
|
||||
}).build();
|
||||
this.quartzVibrantGlass = deco
|
||||
.block("quartz_vibrant_glass",
|
||||
() -> new QuartzLampBlock(defaultProps(Material.GLASS).setLightLevel(b -> 15).notSolid()))
|
||||
() -> new QuartzLampBlock(defaultProps(Material.GLASS).setLightLevel(b -> 15).notSolid()
|
||||
.setAllowsSpawn(neverAllowSpawn)))
|
||||
.addFeatures(AEFeature.DECORATIVE_LIGHTS, AEFeature.QUARTZ_GLASS)
|
||||
.rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -22,12 +22,12 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
import appeng.api.events.LocatableEventAnnounce;
|
||||
import appeng.api.events.LocatableEventAnnounce.LocatableEvent;
|
||||
import appeng.api.features.ILocatable;
|
||||
import appeng.api.features.ILocatableRegistry;
|
||||
import appeng.core.AELog;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public final class LocatableRegistry implements ILocatableRegistry {
|
||||
@@ -35,18 +35,19 @@ public final class LocatableRegistry implements ILocatableRegistry {
|
||||
|
||||
public LocatableRegistry() {
|
||||
this.set = new HashMap<>();
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
MinecraftForge.EVENT_BUS.addListener(this::updateLocatable);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void updateLocatable(final LocatableEventAnnounce e) {
|
||||
private void updateLocatable(final LocatableEventAnnounce e) {
|
||||
if (Platform.isClient()) {
|
||||
return; // IGNORE!
|
||||
}
|
||||
|
||||
if (e.change == LocatableEvent.REGISTER) {
|
||||
AELog.debug("Registering locatable %s: %s", e.target.getLocatableSerial(), e.target);
|
||||
this.set.put(e.target.getLocatableSerial(), e.target);
|
||||
} else if (e.change == LocatableEvent.UNREGISTER) {
|
||||
AELog.debug("Unregistering locatable %s: %s", e.target.getLocatableSerial(), e.target);
|
||||
this.set.remove(e.target.getLocatableSerial());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import appeng.core.sync.packets.BlockTransitionEffectPacket;
|
||||
import appeng.core.sync.packets.ClickPacket;
|
||||
import appeng.core.sync.packets.CompassRequestPacket;
|
||||
import appeng.core.sync.packets.CompassResponsePacket;
|
||||
import appeng.core.sync.packets.CompressedNBTPacket;
|
||||
import appeng.core.sync.packets.ConfigButtonPacket;
|
||||
import appeng.core.sync.packets.ConfigValuePacket;
|
||||
import appeng.core.sync.packets.CraftRequestPacket;
|
||||
@@ -39,6 +38,7 @@ import appeng.core.sync.packets.ItemTransitionEffectPacket;
|
||||
import appeng.core.sync.packets.JEIRecipePacket;
|
||||
import appeng.core.sync.packets.LightningPacket;
|
||||
import appeng.core.sync.packets.MEFluidInventoryUpdatePacket;
|
||||
import appeng.core.sync.packets.MEInterfaceUpdatePacket;
|
||||
import appeng.core.sync.packets.MEInventoryUpdatePacket;
|
||||
import appeng.core.sync.packets.MatterCannonPacket;
|
||||
import appeng.core.sync.packets.MockExplosionPacket;
|
||||
@@ -101,7 +101,7 @@ public class BasePacketHandler {
|
||||
|
||||
PACKET_ASSEMBLER_ANIMATION(AssemblerAnimationPacket.class, AssemblerAnimationPacket::new),
|
||||
|
||||
PACKET_COMPRESSED_NBT(CompressedNBTPacket.class, CompressedNBTPacket::new),
|
||||
PACKET_ME_INTERFACE_UPDATE(MEInterfaceUpdatePacket.class, MEInterfaceUpdatePacket::new),
|
||||
|
||||
PACKET_PAINTED_ENTITY(PaintedEntityPacket.class, PaintedEntityPacket::new),
|
||||
|
||||
|
||||
@@ -19,13 +19,9 @@
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -41,7 +37,6 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.network.NetworkDirection;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
import appeng.fluids.client.gui.FluidTerminalScreen;
|
||||
@@ -55,8 +50,6 @@ import appeng.fluids.util.AEFluidStack;
|
||||
public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
private static final int UNCOMPRESSED_PACKET_BYTE_LIMIT = 16 * 1024 * 1024;
|
||||
private static final int OPERATION_BYTE_LIMIT = 2 * 1024;
|
||||
private static final int TEMP_BUFFER_SIZE = 1024;
|
||||
private static final int STREAM_MASK = 0xff;
|
||||
|
||||
// input.
|
||||
@Nullable
|
||||
@@ -66,47 +59,18 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
|
||||
@Nullable
|
||||
private final PacketBuffer data;
|
||||
@Nullable
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
private int writtenBytes = 0;
|
||||
private boolean empty = true;
|
||||
|
||||
public MEFluidInventoryUpdatePacket(final PacketBuffer stream) {
|
||||
this.data = null;
|
||||
this.compressFrame = null;
|
||||
this.list = new LinkedList<>();
|
||||
this.ref = stream.readByte();
|
||||
|
||||
try (final GZIPInputStream gzReader = new GZIPInputStream(new InputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
if (stream.readableBytes() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stream.readByte() & STREAM_MASK;
|
||||
}
|
||||
})) {
|
||||
|
||||
final PacketBuffer uncompressed = new PacketBuffer(Unpooled.buffer(stream.readableBytes()));
|
||||
final byte[] tmp = new byte[TEMP_BUFFER_SIZE];
|
||||
|
||||
while (gzReader.available() != 0) {
|
||||
final int bytes = gzReader.read(tmp);
|
||||
|
||||
if (bytes > 0) {
|
||||
uncompressed.writeBytes(tmp, 0, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
while (uncompressed.readableBytes() > 0) {
|
||||
this.list.add(AEFluidStack.fromPacket(uncompressed));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to decompress packet.", e);
|
||||
while (stream.readableBytes() > 0) {
|
||||
this.list.add(AEFluidStack.fromPacket(stream));
|
||||
}
|
||||
|
||||
this.empty = this.list.isEmpty();
|
||||
}
|
||||
|
||||
@@ -121,14 +85,6 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
this.data = new PacketBuffer(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
this.data.writeInt(this.getPacketID());
|
||||
this.data.writeByte(this.ref);
|
||||
|
||||
this.compressFrame = new GZIPOutputStream(new OutputStream() {
|
||||
@Override
|
||||
public void write(final int value) {
|
||||
MEFluidInventoryUpdatePacket.this.data.writeByte(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
@@ -145,28 +101,19 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
@Nullable
|
||||
@Override
|
||||
public IPacket<?> toPacket(NetworkDirection direction) {
|
||||
try {
|
||||
this.compressFrame.close();
|
||||
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
} catch (final IOException e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
}
|
||||
|
||||
public void appendFluid(final IAEFluidStack fs) throws IOException, BufferOverflowException {
|
||||
final PacketBuffer tmp = new PacketBuffer(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
fs.writeToPacket(tmp);
|
||||
|
||||
this.compressFrame.flush();
|
||||
if (this.writtenBytes + tmp.readableBytes() > UNCOMPRESSED_PACKET_BYTE_LIMIT) {
|
||||
throw new BufferOverflowException();
|
||||
} else {
|
||||
this.writtenBytes += tmp.readableBytes();
|
||||
this.compressFrame.write(tmp.array(), 0, tmp.readableBytes());
|
||||
this.data.writeBytes(tmp.array(), 0, tmp.readableBytes());
|
||||
this.empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-44
@@ -18,13 +18,7 @@
|
||||
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
@@ -32,7 +26,6 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.CompressedStreamTools;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
@@ -41,55 +34,24 @@ import appeng.client.gui.implementations.InterfaceTerminalScreen;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
|
||||
//TODO, this is pointless, NBT is already compressed when written to a PacketBuffer.
|
||||
public class CompressedNBTPacket extends BasePacket {
|
||||
public class MEInterfaceUpdatePacket extends BasePacket {
|
||||
|
||||
// input.
|
||||
private final CompoundNBT in;
|
||||
// output...
|
||||
private final PacketBuffer data;
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
public CompressedNBTPacket(final PacketBuffer stream) {
|
||||
public MEInterfaceUpdatePacket(final PacketBuffer stream) {
|
||||
this.data = null;
|
||||
this.compressFrame = null;
|
||||
|
||||
try (DataInputStream inStream = new DataInputStream(new GZIPInputStream(new InputStream() {
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
if (stream.readableBytes() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stream.readByte() & 0xff;
|
||||
}
|
||||
}))) {
|
||||
this.in = CompressedStreamTools.read(inStream);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to decompress packet.", e);
|
||||
}
|
||||
this.in = stream.readCompoundTag();
|
||||
}
|
||||
|
||||
// api
|
||||
public CompressedNBTPacket(final CompoundNBT din) throws IOException {
|
||||
|
||||
public MEInterfaceUpdatePacket(final CompoundNBT din) throws IOException {
|
||||
this.in = null;
|
||||
this.data = new PacketBuffer(Unpooled.buffer(2048));
|
||||
this.data.writeInt(this.getPacketID());
|
||||
|
||||
this.in = din;
|
||||
|
||||
this.compressFrame = new GZIPOutputStream(new OutputStream() {
|
||||
|
||||
@Override
|
||||
public void write(final int value) {
|
||||
CompressedNBTPacket.this.data.writeByte(value);
|
||||
}
|
||||
});
|
||||
|
||||
CompressedStreamTools.write(din, new DataOutputStream(this.compressFrame));
|
||||
this.compressFrame.close();
|
||||
|
||||
this.data.writeCompoundTag(din);
|
||||
this.configureWrite(this.data);
|
||||
}
|
||||
|
||||
@@ -19,12 +19,10 @@
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -45,7 +43,6 @@ import appeng.client.gui.implementations.CraftConfirmScreen;
|
||||
import appeng.client.gui.implementations.CraftingCPUScreen;
|
||||
import appeng.client.gui.implementations.MEMonitorableScreen;
|
||||
import appeng.client.gui.implementations.NetworkStatusScreen;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
import appeng.util.item.AEItemStack;
|
||||
@@ -53,8 +50,6 @@ import appeng.util.item.AEItemStack;
|
||||
public class MEInventoryUpdatePacket extends BasePacket {
|
||||
private static final int UNCOMPRESSED_PACKET_BYTE_LIMIT = 16 * 1024 * 1024;
|
||||
private static final int OPERATION_BYTE_LIMIT = 2 * 1024;
|
||||
private static final int TEMP_BUFFER_SIZE = 1024;
|
||||
private static final int STREAM_MASK = 0xff;
|
||||
|
||||
// input.
|
||||
@Nullable
|
||||
@@ -64,48 +59,18 @@ public class MEInventoryUpdatePacket extends BasePacket {
|
||||
|
||||
@Nullable
|
||||
private final PacketBuffer data;
|
||||
@Nullable
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
private int writtenBytes = 0;
|
||||
private boolean empty = true;
|
||||
|
||||
public MEInventoryUpdatePacket(final PacketBuffer stream) {
|
||||
this.data = null;
|
||||
this.compressFrame = null;
|
||||
this.list = new ArrayList<>();
|
||||
this.ref = stream.readByte();
|
||||
|
||||
// int originalBytes = stream.readableBytes();
|
||||
|
||||
try (GZIPInputStream gzReader = new GZIPInputStream(new InputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
if (stream.readableBytes() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stream.readByte() & STREAM_MASK;
|
||||
}
|
||||
})) {
|
||||
final PacketBuffer uncompressed = new PacketBuffer(Unpooled.buffer(stream.readableBytes()));
|
||||
final byte[] tmp = new byte[TEMP_BUFFER_SIZE];
|
||||
|
||||
while (gzReader.available() != 0) {
|
||||
final int bytes = gzReader.read(tmp);
|
||||
|
||||
if (bytes > 0) {
|
||||
uncompressed.writeBytes(tmp, 0, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
while (uncompressed.readableBytes() > 0) {
|
||||
this.list.add(AEItemStack.fromPacket(uncompressed));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to decompress packet.", e);
|
||||
while (stream.readableBytes() > 0) {
|
||||
this.list.add(AEItemStack.fromPacket(stream));
|
||||
}
|
||||
|
||||
this.empty = this.list.isEmpty();
|
||||
}
|
||||
|
||||
@@ -120,14 +85,6 @@ public class MEInventoryUpdatePacket extends BasePacket {
|
||||
this.data = new PacketBuffer(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
this.data.writeInt(this.getPacketID());
|
||||
this.data.writeByte(this.ref);
|
||||
|
||||
this.compressFrame = new GZIPOutputStream(new OutputStream() {
|
||||
@Override
|
||||
public void write(final int value) {
|
||||
MEInventoryUpdatePacket.this.data.writeByte(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
@@ -156,28 +113,19 @@ public class MEInventoryUpdatePacket extends BasePacket {
|
||||
@Nullable
|
||||
@Override
|
||||
public IPacket<?> toPacket(NetworkDirection direction) {
|
||||
try {
|
||||
this.compressFrame.close();
|
||||
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
} catch (final IOException e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
}
|
||||
|
||||
public void appendItem(final IAEItemStack is) throws IOException, BufferOverflowException {
|
||||
final PacketBuffer tmp = new PacketBuffer(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
is.writeToPacket(tmp);
|
||||
|
||||
this.compressFrame.flush();
|
||||
if (this.writtenBytes + tmp.readableBytes() > UNCOMPRESSED_PACKET_BYTE_LIMIT) {
|
||||
throw new BufferOverflowException();
|
||||
} else {
|
||||
this.writtenBytes += tmp.readableBytes();
|
||||
this.compressFrame.write(tmp.array(), 0, tmp.readableBytes());
|
||||
this.data.writeBytes(tmp.array(), 0, tmp.readableBytes());
|
||||
this.empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,8 @@ package appeng.decorative.solid;
|
||||
|
||||
import net.minecraft.block.AbstractGlassBlock;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.Direction;
|
||||
|
||||
import appeng.helpers.AEMaterials;
|
||||
|
||||
public class QuartzGlassBlock extends AbstractGlassBlock {
|
||||
|
||||
public QuartzGlassBlock(Properties props) {
|
||||
@@ -33,8 +30,7 @@ public class QuartzGlassBlock extends AbstractGlassBlock {
|
||||
|
||||
@Override
|
||||
public boolean isSideInvisible(BlockState state, BlockState adjacentBlockState, Direction side) {
|
||||
final Material mat = adjacentBlockState.getMaterial();
|
||||
if (mat == Material.GLASS || mat == AEMaterials.GLASS) {
|
||||
if (adjacentBlockState.getBlock() instanceof QuartzGlassBlock) {
|
||||
if (adjacentBlockState.getRenderType() == state.getRenderType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
import appeng.block.AEBaseBlock;
|
||||
import appeng.core.worlddata.WorldData;
|
||||
@@ -43,11 +42,10 @@ public class SkyStoneBlock extends AEBaseBlock {
|
||||
super(props);
|
||||
this.type = type;
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
MinecraftForge.EVENT_BUS.addListener(this::breakFaster);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void breakFaster(final PlayerEvent.BreakSpeed event) {
|
||||
private void breakFaster(final PlayerEvent.BreakSpeed event) {
|
||||
if (event.getState().getBlock() == this && event.getPlayer() != null) {
|
||||
final ItemStack is = event.getPlayer().getItemStackFromSlot(EquipmentSlotType.MAINHAND);
|
||||
int level = -1;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
package appeng.entity;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.features.AEFeature;
|
||||
@@ -35,12 +36,27 @@ import appeng.client.EffectType;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.items.misc.CrystalSeedItem;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public final class GrowingCrystalEntity extends AEBaseItemEntity {
|
||||
|
||||
public static EntityType<GrowingCrystalEntity> TYPE;
|
||||
|
||||
// Growth tick progress per tick by number of adjacent accelerators
|
||||
// Expressed as 1/1000th of a growth tick, applied to progress_1000
|
||||
// each time this entity ticks.
|
||||
private static final int[] GROWTH_TICK_PROGRESS = { 1, // no accelerators
|
||||
40, // 1 accelerator
|
||||
92, // 2 accelerators
|
||||
159, // 3 accelerators
|
||||
247, // 4 accelerators
|
||||
361, // 5 accelerators
|
||||
509 // 6 accelerators
|
||||
};
|
||||
|
||||
/**
|
||||
* The accumulated progress towards a single growth tick of the crystal in
|
||||
* 1/1000th of a growth tick.
|
||||
*/
|
||||
private int progress_1000 = 0;
|
||||
|
||||
public GrowingCrystalEntity(EntityType<? extends GrowingCrystalEntity> type, World world) {
|
||||
@@ -56,126 +72,140 @@ public final class GrowingCrystalEntity extends AEBaseItemEntity {
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
final ItemStack is = this.getItem();
|
||||
final Item gc = is.getItem();
|
||||
|
||||
if (!(gc instanceof IGrowableCrystal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyGrowthTick((IGrowableCrystal) gc, is);
|
||||
}
|
||||
|
||||
private void applyGrowthTick(IGrowableCrystal cry, ItemStack is) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.IN_WORLD_PURIFICATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemStack is = this.getItem();
|
||||
final Item gc = is.getItem();
|
||||
final int x = MathHelper.floor(this.getPosX());
|
||||
final int y = MathHelper.floor((this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0D);
|
||||
final int z = MathHelper.floor(this.getPosZ());
|
||||
|
||||
if (gc instanceof IGrowableCrystal) // if it changes this just stops being an issue...
|
||||
{
|
||||
final int j = MathHelper.floor(this.getPosX());
|
||||
final int i = MathHelper.floor((this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0D);
|
||||
final int k = MathHelper.floor(this.getPosZ());
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
final BlockState state = this.world.getBlockState(pos);
|
||||
|
||||
final BlockState state = this.world.getBlockState(new BlockPos(j, i, k));
|
||||
final Material mat = state.getMaterial();
|
||||
final IGrowableCrystal cry = (IGrowableCrystal) is.getItem();
|
||||
final float multiplier = cry.getMultiplier(state, world, pos);
|
||||
|
||||
final float multiplier = cry.getMultiplier(state.getBlock(), mat);
|
||||
final int speed = (int) Math.max(1, this.getSpeed(j, i, k) * multiplier);
|
||||
if (multiplier <= 0) {
|
||||
// Crystal is in unsuitable material, reset progress and quit
|
||||
this.progress_1000 = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isClient = Platform.isClient();
|
||||
final int progressPerTick = (int) Math.max(1, this.getSpeed(pos) * multiplier);
|
||||
|
||||
if (mat.isLiquid()) {
|
||||
if (isClient) {
|
||||
this.progress_1000++;
|
||||
} else {
|
||||
this.progress_1000 += speed;
|
||||
}
|
||||
} else {
|
||||
if (world.isRemote()) {
|
||||
// On the client, we reuse the growth-tick-progress
|
||||
// as a tick-counter for particle effects
|
||||
int len = getTicksBetweenParticleEffects(progressPerTick);
|
||||
if (++this.progress_1000 >= len) {
|
||||
this.progress_1000 = 0;
|
||||
AppEng.proxy.spawnEffect(EffectType.Vibrant, this.world, this.getPosX(), this.getPosY() + 0.2,
|
||||
this.getPosZ(), null);
|
||||
}
|
||||
} else {
|
||||
this.progress_1000 += progressPerTick;
|
||||
|
||||
if (isClient) {
|
||||
int len = 40;
|
||||
if (this.progress_1000 >= 1000) {
|
||||
// We need to copy the stack or the change detection will not work and not sync
|
||||
// this new stack to the client
|
||||
ItemStack newItem = is.copy();
|
||||
|
||||
if (speed > 2) {
|
||||
len = 20;
|
||||
}
|
||||
|
||||
if (speed > 90) {
|
||||
len = 15;
|
||||
}
|
||||
|
||||
if (speed > 150) {
|
||||
len = 10;
|
||||
}
|
||||
|
||||
if (speed > 240) {
|
||||
len = 7;
|
||||
}
|
||||
|
||||
if (speed > 360) {
|
||||
len = 3;
|
||||
}
|
||||
|
||||
if (speed > 500) {
|
||||
len = 1;
|
||||
}
|
||||
|
||||
if (this.progress_1000 >= len) {
|
||||
this.progress_1000 = 0;
|
||||
AppEng.proxy.spawnEffect(EffectType.Vibrant, this.world, this.getPosX(), this.getPosY() + 0.2,
|
||||
this.getPosZ(), null);
|
||||
}
|
||||
} else {
|
||||
if (this.progress_1000 > 1000) {
|
||||
// If we did not use a while loop here, the fastest growth for a crystal
|
||||
// would be limited to a minimum of 30 seconds (based on 600 required growth
|
||||
// ticks).
|
||||
// Should a crystal decide to use a high multiplier for a certain material,
|
||||
// it should be possible to go faster.
|
||||
do {
|
||||
newItem = cry.triggerGrowth(newItem);
|
||||
this.progress_1000 -= 1000;
|
||||
// We need to copy the stack or the change detection will not work and not sync
|
||||
// this new stack to the client
|
||||
ItemStack newItem = cry.triggerGrowth(is.copy());
|
||||
this.setItem(newItem);
|
||||
}
|
||||
// We assume that if the item changes, the process is complete and we can break
|
||||
} while (this.progress_1000 >= 1000 && newItem.getItem() == is.getItem());
|
||||
|
||||
this.setItem(newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getSpeed(final int x, final int y, final int z) {
|
||||
final int per = 80;
|
||||
final float mul = 0.3f;
|
||||
|
||||
int qty = 0;
|
||||
|
||||
if (this.isAccelerated(x + 1, y, z)) {
|
||||
qty += per + qty * mul;
|
||||
private static int getTicksBetweenParticleEffects(int progressPerTick) {
|
||||
if (progressPerTick > 500) {
|
||||
return 1; // 20 times per second
|
||||
} else if (progressPerTick > 360) {
|
||||
return 3;
|
||||
} else if (progressPerTick > 240) {
|
||||
return 7;
|
||||
} else if (progressPerTick > 150) {
|
||||
return 10;
|
||||
} else if (progressPerTick > 90) {
|
||||
return 15;
|
||||
} else if (progressPerTick > 2) {
|
||||
return 20;
|
||||
} else {
|
||||
return 40; // Every 2 seconds
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y + 1, z)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y, z + 1)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x - 1, y, z)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y - 1, z)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y, z - 1)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
return qty;
|
||||
}
|
||||
|
||||
private boolean isAccelerated(final int x, final int y, final int z) {
|
||||
final TileEntity te = this.world.getTileEntity(new BlockPos(x, y, z));
|
||||
/**
|
||||
* Gets the extra progress per tick in 1/1000th of a growth tick based on the
|
||||
* surrounding accelerators.
|
||||
*/
|
||||
private int getSpeed(BlockPos pos) {
|
||||
int acceleratorCount = getAcceleratorCount(pos);
|
||||
|
||||
if (acceleratorCount < 0) {
|
||||
return GROWTH_TICK_PROGRESS[0];
|
||||
} else if (acceleratorCount >= GROWTH_TICK_PROGRESS.length) {
|
||||
return GROWTH_TICK_PROGRESS[GROWTH_TICK_PROGRESS.length - 1];
|
||||
} else {
|
||||
return GROWTH_TICK_PROGRESS[acceleratorCount];
|
||||
}
|
||||
}
|
||||
|
||||
private int getAcceleratorCount(BlockPos pos) {
|
||||
int count = 0;
|
||||
|
||||
BlockPos.Mutable testPos = new BlockPos.Mutable();
|
||||
for (Direction direction : Direction.values()) {
|
||||
if (this.isPoweredAccelerator(testPos.func_239622_a_(pos, direction))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private boolean isPoweredAccelerator(BlockPos pos) {
|
||||
final TileEntity te = this.world.getTileEntity(pos);
|
||||
|
||||
return te instanceof ICrystalGrowthAccelerator && ((ICrystalGrowthAccelerator) te).isPowered();
|
||||
}
|
||||
|
||||
// Don't let seeds "float" on water surface
|
||||
@Override
|
||||
protected void applyFloatMotion() {
|
||||
ItemStack item = getItem();
|
||||
|
||||
// Make ungrown seeds sink, and fully grown seeds bouyant allowing for
|
||||
// automation based around dropping seeds between 5 CGAs, then catchiung
|
||||
// them on their way up.
|
||||
if (item.getItem() instanceof CrystalSeedItem) {
|
||||
Vector3d v = this.getMotion();
|
||||
|
||||
// Apply a much smaller acceleration to make them slowly sink
|
||||
double yAccel = this.hasNoGravity() ? 0 : -0.002;
|
||||
|
||||
// Apply the x/z slow-down, and the y acceleration
|
||||
this.setMotion(v.x * 0.99, v.y + yAccel, v.z * 0.99);
|
||||
|
||||
return;
|
||||
}
|
||||
super.applyFloatMotion();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -37,15 +37,18 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
|
||||
private final int facades = 6;
|
||||
private final CableBusStorage storage;
|
||||
private final Runnable changeCallback;
|
||||
|
||||
public FacadeContainer(final CableBusStorage cbs) {
|
||||
public FacadeContainer(final CableBusStorage cbs, Runnable changeCallback) {
|
||||
this.storage = cbs;
|
||||
this.changeCallback = changeCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addFacade(final IFacadePart a) {
|
||||
if (this.getFacade(a.getSide()) == null) {
|
||||
this.storage.setFacade(a.getSide().ordinal(), a);
|
||||
this.notifyChange();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -56,6 +59,7 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
if (side != null && side != AEPartLocation.INTERNAL) {
|
||||
if (this.storage.getFacade(side.ordinal()) != null) {
|
||||
this.storage.setFacade(side.ordinal(), null);
|
||||
this.notifyChange();
|
||||
if (host != null) {
|
||||
host.markForUpdate();
|
||||
}
|
||||
@@ -84,6 +88,7 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
this.storage.setFacade(x, newFacades[x]);
|
||||
}
|
||||
this.notifyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,4 +180,9 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void notifyChange() {
|
||||
this.changeCallback.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -96,16 +96,15 @@ public class FluidImportBusPart extends SharedFluidBusPart {
|
||||
}
|
||||
|
||||
final TileEntity te = this.getConnectedTE();
|
||||
LazyOptional<IFluidHandler> fhOpt = LazyOptional.empty();
|
||||
if (te != null) {
|
||||
te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, this.getSide().getFacing().getOpposite());
|
||||
}
|
||||
if (fhOpt.isPresent()) {
|
||||
try {
|
||||
final IFluidHandler fh = fhOpt.orElse(null);
|
||||
final IMEMonitor<IAEFluidStack> inv = this.getProxy().getStorage().getInventory(this.getChannel());
|
||||
LazyOptional<IFluidHandler> fhOpt = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
|
||||
this.getSide().getFacing().getOpposite());
|
||||
|
||||
if (fhOpt.isPresent()) {
|
||||
try {
|
||||
final IFluidHandler fh = fhOpt.orElseThrow(() -> new IllegalStateException());
|
||||
final IMEMonitor<IAEFluidStack> inv = this.getProxy().getStorage().getInventory(this.getChannel());
|
||||
|
||||
if (fh != null) {
|
||||
final FluidStack fluidStack = fh.drain(this.calculateAmountToSend(), FluidAction.SIMULATE);
|
||||
|
||||
if (this.filterEnabled() && !this.isInFilter(fluidStack)) {
|
||||
@@ -128,12 +127,11 @@ public class FluidImportBusPart extends SharedFluidBusPart {
|
||||
}
|
||||
|
||||
return TickRateModulation.IDLE;
|
||||
} catch (GridAccessException e) {
|
||||
// skip
|
||||
}
|
||||
} catch (GridAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,17 +24,19 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.util.ITooltipFlag;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemModelsProperties;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.tags.ITag;
|
||||
import net.minecraft.util.IItemProvider;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
@@ -43,6 +45,7 @@ import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import appeng.api.implementations.items.IGrowableCrystal;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.localization.ButtonToolTips;
|
||||
import appeng.entity.GrowingCrystalEntity;
|
||||
import appeng.items.AEBaseItem;
|
||||
@@ -96,8 +99,24 @@ public class CrystalSeedItem extends AEBaseItem implements IGrowableCrystal {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMultiplier(final Block blk, final Material mat) {
|
||||
return 0.5f;
|
||||
public float getMultiplier(BlockState state, @Nullable World world, @Nullable BlockPos pos) {
|
||||
|
||||
// Check for the improved fluid tag and return the improved multiplier
|
||||
String improvedFluidTagName = AEConfig.instance().getImprovedFluidTag();
|
||||
if (improvedFluidTagName != null) {
|
||||
ITag<Fluid> tag = FluidTags.getCollection().get(new ResourceLocation(improvedFluidTagName));
|
||||
if (tag != null && state.getFluidState().isTagged(tag)) {
|
||||
return AEConfig.instance().getImprovedFluidMultiplier();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for the normal supported fluid
|
||||
if (world != null && world.func_234923_W_() == World.field_234919_h_) {
|
||||
// In the nether, use Lava as the "normal" fluid
|
||||
return state.getFluidState().isTagged(FluidTags.LAVA) ? 1 : 0;
|
||||
} else {
|
||||
return state.getFluidState().isTagged(FluidTags.WATER) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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;
|
||||
@@ -326,21 +324,21 @@ public class ColorApplicatorItem extends AEBasePoweredItem
|
||||
return w.setBlockState(pos, newState);
|
||||
}
|
||||
|
||||
if (blk instanceof CableBusBlock && p != null) {
|
||||
return ((CableBusBlock) blk).recolorBlock(w, pos, side, newColor.dye, p);
|
||||
}
|
||||
|
||||
TileEntity be = w.getTileEntity(pos);
|
||||
if (be instanceof IColorableTile) {
|
||||
IColorableTile ct = (IColorableTile) be;
|
||||
AEColor c = ct.getColor();
|
||||
if (c != newColor) {
|
||||
ct.recolourBlock(side, newColor, null);
|
||||
ct.recolourBlock(side, newColor, p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blk instanceof CableBusBlock && p != null) {
|
||||
return ((CableBusBlock) blk).recolorBlock(w, pos, side, newColor.dye, p);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,6 @@ public class Grid implements IGrid {
|
||||
}
|
||||
|
||||
gridNode.getGridProxy().gridChanged();
|
||||
// postEventTo( gridNode, networkChanged );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -327,8 +327,9 @@ public class GridNode implements IGridNode, IPathItem {
|
||||
|
||||
@Override
|
||||
public void setPlayerID(final int playerID) {
|
||||
if (playerID >= 0) {
|
||||
if (playerID >= 0 && this.playerID != playerID) {
|
||||
this.playerID = playerID;
|
||||
gridProxy.onGridNotification(GridNotification.OWNER_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+14
-2
@@ -81,8 +81,16 @@ public class SecurityCache implements ISecurityGrid {
|
||||
private void updateSecurityKey() {
|
||||
final long lastCode = this.securityKey;
|
||||
|
||||
/**
|
||||
* Placing a security station will propagate the security station's owner to all
|
||||
* connected grid nodes to prevent the network from not reforming due to
|
||||
* different owners later.
|
||||
*/
|
||||
int newOwner = -1;
|
||||
if (this.securityProvider.size() == 1) {
|
||||
this.securityKey = this.securityProvider.get(0).getSecurityKey();
|
||||
ISecurityProvider securityProvider = this.securityProvider.get(0);
|
||||
this.securityKey = securityProvider.getSecurityKey();
|
||||
newOwner = securityProvider.getOwner();
|
||||
} else {
|
||||
this.securityKey = -1;
|
||||
}
|
||||
@@ -90,7 +98,11 @@ public class SecurityCache implements ISecurityGrid {
|
||||
if (lastCode != this.securityKey) {
|
||||
this.getGrid().postEvent(new MENetworkSecurityChange());
|
||||
for (final IGridNode n : this.getGrid().getNodes()) {
|
||||
((GridNode) n).setLastSecurityKey(this.securityKey);
|
||||
GridNode gridNode = (GridNode) n;
|
||||
gridNode.setLastSecurityKey(this.securityKey);
|
||||
if (gridNode.getPlayerID() != newOwner) {
|
||||
gridNode.setPlayerID(newOwner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.Iterator;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
@@ -159,12 +158,16 @@ public class QuantumCluster implements ILocatable, IAECluster {
|
||||
if (qc != null) {
|
||||
final World theWorld = qc.center.getWorld();
|
||||
if (!qc.isDestroyed) {
|
||||
ChunkPos cPos = new ChunkPos(qc.center.getPos());
|
||||
if (theWorld.getChunkProvider().isChunkLoaded(cPos)) {
|
||||
// In future versions, we might actually want to delay the entire registration
|
||||
// until the center
|
||||
// tile begins ticking normally.
|
||||
if (theWorld.isBlockLoaded(qc.center.getPos())) {
|
||||
final World cur = theWorld.getServer().getWorld(theWorld.func_234923_W_());
|
||||
|
||||
final TileEntity te = theWorld.getTileEntity(qc.center.getPos());
|
||||
return te != qc.center || theWorld != cur;
|
||||
} else {
|
||||
AELog.warn("Found a registered QNB with serial %s whose chunk seems to be unloaded: %s", qe, qc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,4 +278,17 @@ public class QuantumCluster implements ILocatable, IAECluster {
|
||||
private void setRing(final QuantumBridgeTileEntity[] ring) {
|
||||
this.Ring = ring;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (center == null) {
|
||||
return "QuantumCluster{no-center}";
|
||||
}
|
||||
|
||||
World world = center.getWorld();
|
||||
BlockPos pos = center.getPos();
|
||||
|
||||
return "QuantumCluster{" + world + "," + pos + "}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -167,7 +167,6 @@ public class AENetworkProxy implements IGridBlock {
|
||||
* short cut!
|
||||
*
|
||||
* @return grid of node
|
||||
*
|
||||
* @throws GridAccessException of node or grid is null
|
||||
*/
|
||||
public IGrid getGrid() throws GridAccessException {
|
||||
@@ -280,6 +279,11 @@ public class AENetworkProxy implements IGridBlock {
|
||||
|
||||
@Override
|
||||
public void onGridNotification(final GridNotification notification) {
|
||||
if (notification == GridNotification.OWNER_CHANGED) {
|
||||
gp.saveChanges();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.gp instanceof CablePart) {
|
||||
((CablePart) this.gp).markForUpdate();
|
||||
}
|
||||
|
||||
@@ -28,4 +28,7 @@ public interface IGridProxyable extends IGridHost {
|
||||
DimensionalCoord getLocation();
|
||||
|
||||
void gridChanged();
|
||||
|
||||
void saveChanges();
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+8
-3
@@ -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));
|
||||
|
||||
+5
-5
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,7 +41,6 @@ import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
@@ -82,7 +81,6 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
private final EnumSet<LayerFlags> myLayerFlags = EnumSet.noneOf(LayerFlags.class);
|
||||
private YesNo hasRedstone = YesNo.UNDECIDED;
|
||||
private IPartHost tcb;
|
||||
// TODO 1.10.2-R - does somebody seriously want to make parts TESR??? Hope not.
|
||||
private boolean requiresDynamicRender = false;
|
||||
private boolean inWorld = false;
|
||||
// Cached collision shape for living entities
|
||||
@@ -125,7 +123,7 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
|
||||
@Override
|
||||
public IFacadeContainer getFacadeContainer() {
|
||||
return new FacadeContainer(this);
|
||||
return new FacadeContainer(this, this::invalidateShapes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1096,11 +1094,7 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
}
|
||||
}
|
||||
|
||||
VoxelShape shape = VoxelShapes.empty();
|
||||
for (final AxisAlignedBB bx : boxes) {
|
||||
shape = VoxelShapes.or(shape, VoxelShapes.create(bx));
|
||||
}
|
||||
return shape;
|
||||
return VoxelShapeCache.get(boxes);
|
||||
}
|
||||
|
||||
private void invalidateShapes() {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, 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.parts;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.shapes.IBooleanFunction;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
|
||||
/**
|
||||
* While creation of a {@link VoxelShape} with
|
||||
* {@link VoxelShapes#create(AxisAlignedBB)} is fast enough, combining voxel
|
||||
* shapes with {@link VoxelShapes#or(VoxelShape, VoxelShape)} or any other
|
||||
* combination method, as well as {@link VoxelShape#simplify()} are <b>extremely
|
||||
* slow</b>. For example: Creating a VoxelShape for a list of 5 bounding boxes
|
||||
* 10,000 times takes about 1.7 seconds.
|
||||
*
|
||||
* <p>
|
||||
* To reduce the impact of this on cables, we introduce a global voxel shape
|
||||
* cache so that cables can share their combined voxel shapes better.
|
||||
*/
|
||||
final class VoxelShapeCache {
|
||||
|
||||
// Why using a List here should not make much of a difference vs. using a Set:
|
||||
// The part's bounding box depends on the side it is attached to, and the sides
|
||||
// are iterated over in a fixed order, meaning the order of bounding boxes
|
||||
// should
|
||||
// be the same for a same set of parts.
|
||||
private static final LoadingCache<List<AxisAlignedBB>, VoxelShape> CACHE = CacheBuilder.newBuilder()//
|
||||
.maximumSize(10000L)//
|
||||
.build(new CacheLoader<List<AxisAlignedBB>, VoxelShape>() {
|
||||
@Override
|
||||
public VoxelShape load(List<AxisAlignedBB> key) {
|
||||
return create(key);
|
||||
}
|
||||
});
|
||||
|
||||
private VoxelShapeCache() {
|
||||
}
|
||||
|
||||
public static VoxelShape get(List<AxisAlignedBB> boxes) {
|
||||
return CACHE.getUnchecked(boxes);
|
||||
}
|
||||
|
||||
private static VoxelShape create(List<AxisAlignedBB> boxes) {
|
||||
if (boxes.isEmpty()) {
|
||||
return VoxelShapes.empty();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
VoxelShape shape = VoxelShapes.create(boxes.get(i));
|
||||
for (; i < boxes.size(); i++) {
|
||||
AxisAlignedBB box = boxes.get(i);
|
||||
shape = VoxelShapes.combine(shape, VoxelShapes.create(box), IBooleanFunction.OR);
|
||||
}
|
||||
return shape.simplify();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<?>>
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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."));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+6
-3
@@ -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))
|
||||
+8
-5
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
+6
-6
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user