- Версия(и) Minecraft
- 1.12.2
@Deprecated
Приветствую! Я тут недавно закончил делать провода и теперь хочу поделиться с Вами тем, что у меня получилось. Не просто расскажу, а попытаюсь объяснить, как это работает.
Итак, давайте порассуждаем. Каким образом можно реализовать провода?
Иметь для каждого провода тайл и каждую секунду передавать енергию?
Не… Начнется лютый лагодром и каким образом понять куда доставлять енергию.
Лучше с помощью алгоритма поиска в ширину(Почему он? Он проходится по всем вершинам графа, то есть он проверит все подключенные провода) проверять все подключенные проводами «поставщики» енергии и «потребители». Всем «поставщикам» енергии выдавать список подключенных «потребителей». Остальное, я думаю вы подчеркнете из прокомментированного класса провода. Там к слову есть и визуальная реализация проводов.
Модель я думаю Вы сможете сделать.
Основная модель - это просто кубик,
а сторона это продолжение кубика вверх.
P.s. Частично использовал исходники мода @iconst_1
Если какие-то ошибки, то укажите.
Хорошо бы конечно переписать этот туториал человеку, который реально знает, что делает т.к. туториалов на эту тему практически нет, только вопросы на форуме forge.(но мечты мечтами) Многие, я думаю, хотят реализовать в своих модах провода(или сеть энергии). Или поправить мою кривую реализацию.
P.P.s пилю другой вариант реализации, должно быть получше.
Приветствую! Я тут недавно закончил делать провода и теперь хочу поделиться с Вами тем, что у меня получилось. Не просто расскажу, а попытаюсь объяснить, как это работает.
Итак, давайте порассуждаем. Каким образом можно реализовать провода?
Иметь для каждого провода тайл и каждую секунду передавать енергию?
Не… Начнется лютый лагодром и каким образом понять куда доставлять енергию.
Лучше с помощью алгоритма поиска в ширину(Почему он? Он проходится по всем вершинам графа, то есть он проверит все подключенные провода) проверять все подключенные проводами «поставщики» енергии и «потребители». Всем «поставщикам» енергии выдавать список подключенных «потребителей». Остальное, я думаю вы подчеркнете из прокомментированного класса провода. Там к слову есть и визуальная реализация проводов.
Java:
public class Wire extends Block{
//Каждое свойство отвечает за то, подключен ли к этой стороне провод или другой участник цепи(true/false)
public static final PropertyBool DOWN = PropertyBool.create("down");
public static final PropertyBool UP = PropertyBool.create("up");
public static final PropertyBool NORTH = PropertyBool.create("north");
public static final PropertyBool SOUTH = PropertyBool.create("south");
public static final PropertyBool WEST = PropertyBool.create("west");
public static final PropertyBool EAST = PropertyBool.create("east");
public Wire() {
super(Material.CIRCUITS);
this.setRegistryName("wire");
this.setUnlocalizedName("wire");
this.setCreativeTab(CommonProxy.redstone_things_tab);
}
//Метод "строящий" сеть, передаем в него мир и стартовую позицию
public ArrayList<BlockPos> buildNetwork(IBlockAccess worldIn, BlockPos start) {
HashSet<BlockPos> checked = new HashSet<>();//список проверенных блоков
ArrayList<BlockPos> generators = new ArrayList<>();//список генераторов, которые будут найдены в сети
ArrayList<BlockPos> storages = new ArrayList<>();//список хранилищ, которые будут найдены в сети
ArrayDeque<BlockPos> queue = new ArrayDeque<>(100);//Очередь - это особенность реализации алгоритма поиска в ширину.
queue.offer(start);//Добавляем стартовую позицию в очередь
checked.add(start);//И сразу добавляем в проверенные
while (!queue.isEmpty()) {//Выполняем пока очередь не пуста
BlockPos nPos = queue.poll();//Этот метод возвращает объект из головы очереди и сразу его удаляет.
//Проверяем не генератор ли стартовая позиция.
TileEntity tile = worldIn.getTileEntity(nPos);
if(tile != null) {
if(tile.hasCapability(EnergyGeneratorCapability.ENERGY_GENERATOR, null)) {// У меня свои капы на генератор и хранилище
generators.add(nPos);
}
}
for (EnumFacing face : EnumFacing.VALUES) {//Циклом прогоняемся по всем возможным "направлением"(не знаю как лучше перевести
BlockPos child = nPos.offset(face);//эта функция возвращает позицию со сдвигом в данном направлении(+1 в этом направлении)
TileEntity tileEntity = worldIn.getTileEntity(child);//получаем тайл
if(tileEntity != null) {
//проверяем, что это, генератор или хранилище
if(tileEntity.hasCapability(EnergyGeneratorCapability.ENERGY_GENERATOR, null)) {
generators.add(child); // и добовлеям их в соответственные списки
}
if(tileEntity.hasCapability(EnergyStorageCapability.ENERGY_STORAGE, null)) {
storages.add(child);// и добовлеям их в соответственные списки
}
}
//Если в списке проверенных нету этой позиции и блок на этой позиции - это провод, добавляем в список
//проверенных + в очередь, чтобы с этой позиции проверить уже другие блоки
if(!checked.contains(child) && worldIn.getBlockState(child).getBlock() instanceof Wire) {
checked.add(child);
queue.addLast(child);//Добавляем в низ очереди
}
}
}
if(!generators.isEmpty()) {//Если есть в сети генераторы
for (int i = 0; i < generators.size(); i++) {//прогоняемся по ним циклом
BlockPos gPos = generators.get(i);
TileEntity tileEntity = worldIn.getTileEntity(gPos);
if(tileEntity != null && tileEntity instanceof GeneratorTile) {
//Проверяем, что они наследают спец класс GeneratorTile, нижке под спойлером есть этот класс
GeneratorTile generator = (GeneratorTile) tileEntity;
generator.setStorages(storages);//устонавливаем в этот генератор список найденных в сети хранилищ
}
}
}
return generators;
}
@Override
public void onBlockDestroyedByPlayer(World worldIn, BlockPos pos, IBlockState state) {
// Когда блок сломали, нам нужно всем проводам вокруг себя дать комманду перестроить сеть.
// Ведь сломав провод мы можем разорвать соединение
for (EnumFacing face : EnumFacing.VALUES) {
BlockPos p = pos.offset(face);
TileEntity tileEntity = worldIn.getTileEntity(p);
if(tileEntity != null && tileEntity instanceof GeneratorTile) {
//Даже если это генератор, мы перестраиваем сеть с его позиции, ведь
//генератор может быть подключен всего одним кабелем
buildNetwork(worldIn, p);
}
if(worldIn.getBlockState(p).getBlock() instanceof Wire) {
//Заставляем провода в округе перестроить сеть
Wire wire = (Wire) worldIn.getBlockState(p).getBlock();
wire.buildNetwork(worldIn, p);
}
}
super.onBlockDestroyedByPlayer(worldIn, pos, state);
}
@Override
public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state) {
//Когда провод установлен нам нужно "построить сеть"
this.buildNetwork(worldIn, pos);
super.onBlockAdded(worldIn, pos, state);
}
@Override
public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) {
// Это даст нам возможность добавлять хранилища/генераторы если они были поставлены рядом
this.buildNetwork(worldIn, pos);
super.neighborChanged(state, worldIn, pos, blockIn, fromPos);
}
//Это метод нужен для проверки можем ли мы текстуркой "соедениться" с другим блоком
public boolean canConnectTo(IBlockAccess world, BlockPos pos, EnumFacing facing){
BlockPos child = pos.offset(facing);
TileEntity tileEntity = world.getTileEntity(child);
if(tileEntity != null) {
if(tileEntity.hasCapability(EnergyStorageCapability.ENERGY_STORAGE, null)) {
//если генератор - да
return true;
}
if(tileEntity.hasCapability(EnergyGeneratorCapability.ENERGY_GENERATOR, null)) {
//если хранилище - да
return true;
}
}
if(world.getBlockState(child).getBlock() instanceof Wire) {
//если провод - да
return true;
}
return false;
}
@Override
public void addCollisionBoxToList(IBlockState state, World world, BlockPos pos, AxisAlignedBB entityBox,
List<AxisAlignedBB> collidingBoxes, Entity entityIn, boolean isActualState) {
//В зависимости от того, какие стороны подключены, выставляем определенную коллизию
if (canConnectTo(world, pos, EnumFacing.UP)) {
addCollisionBoxToList(pos, entityBox, collidingBoxes,
new AxisAlignedBB(0.377, 0, 0.377, 0.623D, 0.623D, 0.623D));
}
if (canConnectTo(world, pos, EnumFacing.UP)) {
addCollisionBoxToList(pos, entityBox, collidingBoxes,
new AxisAlignedBB(0.377, 0.377, 0.377, 0.623D, 1, 0.623D));
}
if (canConnectTo(world, pos, EnumFacing.NORTH)) {
addCollisionBoxToList(pos, entityBox, collidingBoxes,
new AxisAlignedBB(0.377, 0.377, 0, 0.623D, 0.623D, 0.623D));
}
if (canConnectTo(world, pos, EnumFacing.SOUTH)) {
addCollisionBoxToList(pos, entityBox, collidingBoxes,
new AxisAlignedBB(0.377, 0.377, 0.377, 0.623D, 0.623D, 1));
}
if (canConnectTo(world, pos, EnumFacing.EAST)) {
addCollisionBoxToList(pos, entityBox, collidingBoxes,
new AxisAlignedBB(0.377, 0.377, 0.377, 1, 0.623D, 0.623D));
}
if (canConnectTo(world, pos, EnumFacing.WEST)) {
addCollisionBoxToList(pos, entityBox, collidingBoxes,
new AxisAlignedBB(0, 0.377, 0.377, 0.623D, 0.623D, 0.623D));
}
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos) {
// Тоже самое, что и с коллизией
double[] sidebound = new double[6];
sidebound[0]=sidebound[1]=sidebound[2]=0.377D;
sidebound[3]=sidebound[4]=sidebound[5]=0.6231D;
if (canConnectTo(world, pos, EnumFacing.DOWN) == true) {
sidebound[1]=0;
}
if (canConnectTo(world, pos, EnumFacing.UP) == true) {
sidebound[4]=1;
}
if (canConnectTo(world, pos, EnumFacing.NORTH) == true) {
sidebound[2]=0;
}
if (canConnectTo(world, pos, EnumFacing.SOUTH) == true) {
sidebound[5]=1;
}
if (canConnectTo(world, pos, EnumFacing.WEST) == true) {
sidebound[0]=0;
}
if (canConnectTo(world, pos, EnumFacing.EAST) == true) {
sidebound[3]=1;
}
return new AxisAlignedBB(sidebound[0], sidebound[1], sidebound[2], sidebound[3], sidebound[4], sidebound[5]);
}
@Override
protected BlockStateContainer createBlockState() {
//Создаем контейнер для наших "свойств"
return new BlockStateContainer(this, UP, DOWN, NORTH, SOUTH, WEST, EAST);
}
@Override
public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos) {
//Пользуясь методом просто устанавливаем true/false свойствам
// С помощью этого мы будем рендерить(или нет) частичку кабеля с определенной стороны.
return state
.withProperty(DOWN, canConnectTo(world, pos, EnumFacing.DOWN))
.withProperty(UP, canConnectTo(world, pos, EnumFacing.UP))
.withProperty(NORTH, canConnectTo(world, pos, EnumFacing.NORTH))
.withProperty(SOUTH, canConnectTo(world, pos, EnumFacing.SOUTH))
.withProperty(WEST, canConnectTo(world, pos, EnumFacing.WEST))
.withProperty(EAST, canConnectTo(world, pos, EnumFacing.EAST));
}
@Override
public int getMetaFromState(IBlockState state) {
return 0;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public boolean isFullCube(IBlockState state) {
return false;
}
}
Java:
public class GeneratorTile extends TileEntity{
public ArrayList<BlockPos> storages = new ArrayList<>();
public void setStorages(ArrayList<BlockPos> storages) {
this.storages = storages;
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
NBTTagList list = new NBTTagList();
for(int i = 0; i < storages.size(); i++) {
NBTTagCompound tag = NBTUtil.createPosTag(storages.get(i));
list.appendTag(tag);
}
compound.setTag("storages", list);
return compound;
}
@Override
public void readFromNBT(NBTTagCompound compound) {
NBTTagList list = compound.getTagList("storages", Constants.NBT.TAG_COMPOUND);
storages.clear();
for (int i = 0; i < list.tagCount(); i++) {
storages.add(NBTUtil.getPosFromTag(list.getCompoundTagAt(i)));
}
super.readFromNBT(compound);
}
}
Основная модель - это просто кубик,
а сторона это продолжение кубика вверх.
{
"forge_marker": 1,
"defaults": {
"model": "redstonethings:wire",
"transform": "forge:default-block"
},
"variants": {
"down": {
"true": {
"submodel": "redstonethings:wire_side", "x": 180
},
"false": {}
},
"up": {
"true": {
"submodel": "redstonethings:wire_side"
},
"false": {}
},
"north": {
"true": {
"submodel": "redstonethings:wire_side", "x":90
},
"false": {}
},
"south": {
"true": {
"submodel": "redstonethings:wire_side", "x": 270
},
"false": {}
},
"west": {
"true": {
"submodel": "redstonethings:wire_side", "x": 270, "y":90
},
"false": {}
},
"east": {
"true": {
"submodel": "redstonethings:wire_side", "x": 90, "y":90
},
"false": {}
},
"inventory": [{}]
}
}
"forge_marker": 1,
"defaults": {
"model": "redstonethings:wire",
"transform": "forge:default-block"
},
"variants": {
"down": {
"true": {
"submodel": "redstonethings:wire_side", "x": 180
},
"false": {}
},
"up": {
"true": {
"submodel": "redstonethings:wire_side"
},
"false": {}
},
"north": {
"true": {
"submodel": "redstonethings:wire_side", "x":90
},
"false": {}
},
"south": {
"true": {
"submodel": "redstonethings:wire_side", "x": 270
},
"false": {}
},
"west": {
"true": {
"submodel": "redstonethings:wire_side", "x": 270, "y":90
},
"false": {}
},
"east": {
"true": {
"submodel": "redstonethings:wire_side", "x": 90, "y":90
},
"false": {}
},
"inventory": [{}]
}
}
Если какие-то ошибки, то укажите.
Хорошо бы конечно переписать этот туториал человеку, который реально знает, что делает т.к. туториалов на эту тему практически нет, только вопросы на форуме forge.(но мечты мечтами) Многие, я думаю, хотят реализовать в своих модах провода(или сеть энергии). Или поправить мою кривую реализацию.
P.P.s пилю другой вариант реализации, должно быть получше.