mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
WIP autocrafting using java recipe book
work in progress. many edge cases are currently unhandled. will not work at all pre 1.12. (support is planned)
This commit is contained in:
parent
528a9a4431
commit
8928d554a1
6 changed files with 130 additions and 30 deletions
|
@ -61,6 +61,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
|
@ -230,6 +231,7 @@ public class GeyserSession implements CommandSender {
|
|||
|
||||
@Setter
|
||||
private Int2ObjectMap<Recipe> craftingRecipes;
|
||||
private final Set<String> unlockedRecipes;
|
||||
|
||||
/**
|
||||
* Saves a list of all stonecutter recipes, for use in a stonecutter inventory.
|
||||
|
@ -382,6 +384,7 @@ public class GeyserSession implements CommandSender {
|
|||
this.openInventory = null;
|
||||
this.inventoryFuture = CompletableFuture.completedFuture(null);
|
||||
this.craftingRecipes = new Int2ObjectOpenHashMap<>();
|
||||
this.unlockedRecipes = new ObjectOpenHashSet<>();
|
||||
|
||||
this.spawned = false;
|
||||
this.loggedIn = false;
|
||||
|
|
|
@ -27,8 +27,12 @@ package org.geysermc.connector.network.translators.inventory;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCreativeInventoryActionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientPrepareCraftingGridPacket;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
|
@ -552,7 +556,8 @@ public abstract class InventoryTranslator {
|
|||
|
||||
int recipeId = 0;
|
||||
int resultSize = 0;
|
||||
boolean autoCraft;
|
||||
int timesCrafted = 0;
|
||||
boolean autoCraft = false;
|
||||
CraftState craftState = CraftState.START;
|
||||
|
||||
int leftover = 0;
|
||||
|
@ -566,28 +571,30 @@ public abstract class InventoryTranslator {
|
|||
}
|
||||
craftState = CraftState.RECIPE_ID;
|
||||
recipeId = craftAction.getRecipeNetworkId();
|
||||
//System.out.println(session.getCraftingRecipes().get(recipeId));
|
||||
autoCraft = false;
|
||||
break;
|
||||
}
|
||||
// case CRAFT_RECIPE_AUTO: {
|
||||
// AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action;
|
||||
// if (craftState != CraftState.START) {
|
||||
// return rejectRequest(request);
|
||||
// }
|
||||
// craftState = CraftState.RECIPE_ID;
|
||||
// recipeId = autoCraftAction.getRecipeNetworkId();
|
||||
// Recipe recipe = session.getCraftingRecipes().get(recipeId);
|
||||
// System.out.println(recipe);
|
||||
// if (recipe == null) {
|
||||
// return rejectRequest(request);
|
||||
// }
|
||||
//// ClientPrepareCraftingGridPacket packet = new ClientPrepareCraftingGridPacket(session.getOpenInventory().getId(), recipe.getIdentifier(), true);
|
||||
//// session.sendDownstreamPacket(packet);
|
||||
// autoCraft = true;
|
||||
// //TODO: reject transaction if crafting grid is not clear
|
||||
// break;
|
||||
// }
|
||||
case CRAFT_RECIPE_AUTO: {
|
||||
AutoCraftRecipeStackRequestActionData autoCraftAction = (AutoCraftRecipeStackRequestActionData) action;
|
||||
if (craftState != CraftState.START) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
craftState = CraftState.RECIPE_ID;
|
||||
|
||||
recipeId = autoCraftAction.getRecipeNetworkId();
|
||||
if (!plan.getCursor().isEmpty()) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
//reject if crafting grid is not clear
|
||||
int gridSize = inventory.getId() == 0 ? 4 : 9;
|
||||
for (int i = 1; i <= gridSize; i++) {
|
||||
if (!inventory.getItem(i).isEmpty()) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
}
|
||||
autoCraft = true;
|
||||
break;
|
||||
}
|
||||
case CRAFT_RESULTS_DEPRECATED: {
|
||||
CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action;
|
||||
if (craftState != CraftState.RECIPE_ID) {
|
||||
|
@ -599,7 +606,8 @@ public abstract class InventoryTranslator {
|
|||
return rejectRequest(request);
|
||||
}
|
||||
resultSize = deprecatedCraftAction.getResultItems()[0].getCount();
|
||||
if (resultSize <= 0) {
|
||||
timesCrafted = deprecatedCraftAction.getTimesCrafted();
|
||||
if (resultSize <= 0 || timesCrafted <= 0) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
break;
|
||||
|
@ -628,11 +636,45 @@ public abstract class InventoryTranslator {
|
|||
}
|
||||
|
||||
int sourceSlot = bedrockSlotToJava(transferAction.getSource());
|
||||
int destSlot = bedrockSlotToJava(transferAction.getDestination());
|
||||
|
||||
if (autoCraft) {
|
||||
Recipe recipe = session.getCraftingRecipes().get(recipeId);
|
||||
//cannot use java recipe book if recipe is locked
|
||||
if (recipe == null || !session.getUnlockedRecipes().contains(recipe.getIdentifier())) {
|
||||
return rejectRequest(request);
|
||||
}
|
||||
|
||||
boolean cursorDest = isCursor(transferAction.getDestination());
|
||||
boolean makeAll = timesCrafted > 1;
|
||||
if (cursorDest) {
|
||||
makeAll = false;
|
||||
}
|
||||
|
||||
ClientPrepareCraftingGridPacket prepareCraftingPacket = new ClientPrepareCraftingGridPacket(inventory.getId(), recipe.getIdentifier(), makeAll);
|
||||
session.sendDownstreamPacket(prepareCraftingPacket);
|
||||
|
||||
ItemStack output = null;
|
||||
switch (recipe.getType()) {
|
||||
case CRAFTING_SHAPED:
|
||||
output = ((ShapedRecipeData)recipe.getData()).getResult();
|
||||
break;
|
||||
case CRAFTING_SHAPELESS:
|
||||
output = ((ShapelessRecipeData)recipe.getData()).getResult();
|
||||
break;
|
||||
}
|
||||
inventory.setItem(0, GeyserItemStack.from(output), session);
|
||||
|
||||
plan.add(cursorDest ? Click.LEFT : Click.LEFT_SHIFT, 0);
|
||||
plan.execute(true);
|
||||
|
||||
return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet()));
|
||||
}
|
||||
|
||||
if (isCursor(transferAction.getDestination())) {
|
||||
plan.add(Click.LEFT, sourceSlot);
|
||||
craftState = CraftState.DONE;
|
||||
} else {
|
||||
int destSlot = bedrockSlotToJava(transferAction.getDestination());
|
||||
if (leftover != 0) {
|
||||
if (transferAction.getCount() > leftover) {
|
||||
return rejectRequest(request);
|
||||
|
|
|
@ -25,16 +25,14 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.inventory.click;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.window.ClickItemParam;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.DropItemParam;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.WindowActionParam;
|
||||
import com.github.steveice10.mc.protocol.data.game.window.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum Click {
|
||||
LEFT(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK),
|
||||
RIGHT(WindowAction.CLICK_ITEM, ClickItemParam.RIGHT_CLICK),
|
||||
LEFT_SHIFT(WindowAction.SHIFT_CLICK_ITEM, ShiftClickItemParam.LEFT_CLICK),
|
||||
DROP_ONE(WindowAction.DROP_ITEM, DropItemParam.DROP_FROM_SELECTED),
|
||||
DROP_ALL(WindowAction.DROP_ITEM, DropItemParam.DROP_SELECTED_STACK),
|
||||
LEFT_OUTSIDE(WindowAction.CLICK_ITEM, ClickItemParam.LEFT_CLICK),
|
||||
|
|
|
@ -166,11 +166,16 @@ public class ClickPlan {
|
|||
|
||||
GeyserItemStack clicked = simulating ? getItem(action.slot) : inventory.getItem(action.slot);
|
||||
if (translator.getSlotType(action.slot) == SlotType.OUTPUT) {
|
||||
switch (action.click) {
|
||||
case LEFT:
|
||||
case RIGHT:
|
||||
if (cursor.isEmpty() && !clicked.isEmpty()) {
|
||||
setCursor(clicked.copy());
|
||||
} else if (InventoryUtils.canStack(cursor, clicked)) {
|
||||
cursor.add(clicked.getAmount());
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (action.click) {
|
||||
case LEFT:
|
||||
|
@ -195,6 +200,9 @@ public class ClickPlan {
|
|||
clicked.add(1);
|
||||
}
|
||||
break;
|
||||
case LEFT_SHIFT:
|
||||
//TODO
|
||||
break;
|
||||
case DROP_ONE:
|
||||
if (!clicked.isEmpty()) {
|
||||
clicked.sub(1);
|
||||
|
|
|
@ -183,6 +183,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
|||
|
||||
session.sendUpstreamPacket(craftingDataPacket);
|
||||
session.setCraftingRecipes(recipeMap);
|
||||
session.getUnlockedRecipes().clear();
|
||||
session.setStonecutterRecipes(stonecutterRecipeMap);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.UnlockRecipesAction;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerUnlockRecipesPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Translator(packet = ServerUnlockRecipesPacket.class)
|
||||
public class JavaUnlockRecipesTranslator extends PacketTranslator<ServerUnlockRecipesPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerUnlockRecipesPacket packet, GeyserSession session) {
|
||||
if (packet.getAction() == UnlockRecipesAction.REMOVE) {
|
||||
session.getUnlockedRecipes().removeAll(Arrays.asList(packet.getRecipes()));
|
||||
} else {
|
||||
session.getUnlockedRecipes().addAll(Arrays.asList(packet.getRecipes()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue