Search in sources :

Example 1 with ApiError

use of eelfloat.replcraft.exceptions.ApiError in project replcraft by LeeFlemingRepl.

the class WebsocketServer method onMessage.

private void onMessage(WsMessageContext ctx) {
    String nonce = null;
    try {
        JSONObject request = new JSONObject(ctx.message());
        nonce = request.getString("nonce");
        JSONObject response = new JSONObject();
        response.put("ok", true);
        response.put("nonce", nonce);
        Client client = clients.get(ctx);
        String action = request.getString("action");
        WebsocketActionHandler handler = this.apis.get(action);
        if (handler == null)
            throw new ApiError("bad request", "Unknown action");
        if (handler.authenticated() && client.getStructure() == null) {
            String error = client.isInvalidated() ? "Structure was invalidated" : "Connection isn't authenticated yet";
            throw new ApiError("unauthenticated", error);
        }
        if (client.getStructure() != null && !client.getStructure().material.apis.contains(action)) {
            throw new ApiError("bad request", "This structure type doesn't support this API call.");
        }
        String permission = handler.permission();
        if (permission != null) {
            OfflinePlayer player = client.getStructure().getPlayer();
            World world = client.getStructure().getWorld();
            if (!ReplCraft.plugin.permissionProvider.hasPermission(player, world, permission))
                throw new ApiError("bad request", "You lack the permission to make this API call.");
        }
        // --- Threading boundary! ---
        // Any code inside runTask() is run on the main server thread.
        // Any code above this should be non-mutative, functional-only code that should never touch the world.
        String finalNonce = nonce;
        Bukkit.getScheduler().runTask(ReplCraft.plugin, () -> {
            try {
                if (client.getStructure() != null) {
                    double fuelCost = handler.cost().toDouble() * client.getStructure().material.fuelMultiplier;
                    boolean freeFuel = (client.getStructure() != null && ReplCraft.plugin.world_guard && ApiUtil.checkFlagOnStructure(client.getStructure(), ReplCraft.plugin.worldGuard.replcraft_infinite_fuel));
                    if (!freeFuel && !client.useFuel(fuelCost)) {
                        String message = String.format("out of fuel (cost: %s). available strategies: provide %s of %s.", fuelCost, ReplCraft.plugin.consume_from_all ? "ALL" : "ANY", client.getFuelSources());
                        throw new ApiError("out of fuel", message);
                    }
                }
                handler.execute(client, ctx, request, response);
                ctx.send(response.toString());
            } catch (Exception ex) {
                ctx.send(toClientError(ex, finalNonce).toString());
            }
        });
    } catch (Exception ex) {
        ctx.send(toClientError(ex, nonce).toString());
    }
}
Also used : JSONObject(org.json.JSONObject) ApiError(eelfloat.replcraft.exceptions.ApiError) JSONException(org.json.JSONException)

Example 2 with ApiError

use of eelfloat.replcraft.exceptions.ApiError in project replcraft by LeeFlemingRepl.

the class WebsocketServer method toClientError.

private JSONObject toClientError(Exception ex, String nonce) {
    JSONObject json = new JSONObject();
    json.put("ok", false);
    json.put("nonce", nonce);
    if (ex instanceof JSONException) {
        json.put("error", "bad request");
        json.put("message", ex.getMessage());
    } else if (ex instanceof InvalidStructure) {
        json.put("error", "invalid structure");
        json.put("message", ex.getMessage());
    } else if (ex instanceof ApiError) {
        json.put("error", ((ApiError) ex).type);
        json.put("message", ((ApiError) ex).message);
    } else {
        json.put("error", "internal error");
        json.put("message", "an internal server error occurred (this is a bug)");
        ex.printStackTrace();
    }
    return json;
}
Also used : InvalidStructure(eelfloat.replcraft.exceptions.InvalidStructure) JSONObject(org.json.JSONObject) JSONException(org.json.JSONException) ApiError(eelfloat.replcraft.exceptions.ApiError)

Example 3 with ApiError

use of eelfloat.replcraft.exceptions.ApiError in project replcraft by LeeFlemingRepl.

the class Craft method execute.

@Override
public void execute(Client client, WsMessageContext ctx, JSONObject request, JSONObject response) throws ApiError {
    JSONArray ingredients = request.getJSONArray("ingredients");
    Inventory output = ApiUtil.getContainer(ApiUtil.getBlock(client, request), "output container");
    ApiUtil.checkProtectionPlugins(client.getStructure().minecraft_uuid, output.getLocation());
    class CraftingHelper {

        final ItemStack item;

        final Location location;

        final int index;

        /**
         * The number of items that have been consumed from this helper
         */
        int timesUsed = 0;

        /**
         * The number of times this helper was included in the client's provided recipe
         */
        int timesReferenced = 0;

        CraftingHelper(ItemStack item, Location location, int index) {
            this.item = item;
            this.location = location;
            this.index = index;
        }
    }
    // A list of crafting helpers. Crafting helpers pointing at the same location are duplicated
    // in the list. Some slots are null to account for spaces.
    ArrayList<CraftingHelper> items = new ArrayList<>();
    for (int i = 0; i < ingredients.length(); i++) {
        if (ingredients.isNull(i)) {
            items.add(null);
            continue;
        }
        JSONObject reference = ingredients.getJSONObject(i);
        Block block = ApiUtil.getBlock(client, reference);
        int index = reference.getInt("index");
        ItemStack item = ApiUtil.getItem(block, String.format("ingredient %d block", i), index);
        Location location = block.getLocation();
        ApiUtil.checkProtectionPlugins(client.getStructure().minecraft_uuid, location);
        CraftingHelper new_or_existing = items.stream().filter(helper -> helper != null && helper.location.equals(location) && helper.index == index).findFirst().orElseGet(() -> new CraftingHelper(item, location, index));
        new_or_existing.timesReferenced += 1;
        items.add(new_or_existing);
    }
    boolean crafted = false;
    Iterator<Recipe> iter = Bukkit.recipeIterator();
    recipes: while (!crafted && iter.hasNext()) {
        Recipe next = iter.next();
        if (next instanceof ShapedRecipe) {
            Map<Character, ItemStack> ingredientMap = ((ShapedRecipe) next).getIngredientMap();
            String[] rows = ((ShapedRecipe) next).getShape();
            for (int row = 0; row < rows.length; row++) {
                for (int col = 0; col < rows[row].length(); col++) {
                    ItemStack stack = ingredientMap.get(rows[row].charAt(col));
                    int i = row * rows.length + col;
                    if (i >= items.size())
                        continue recipes;
                    CraftingHelper ingredient = items.get(i);
                    if (stack == null && ingredient != null) {
                        // Reset used items and try next recipe
                        for (CraftingHelper item : items) if (item != null)
                            item.timesUsed = 0;
                        continue recipes;
                    }
                    if (stack == null) {
                        // No item to check here and no item provided, move on to next slot
                        continue;
                    }
                    if (ingredient == null || stack.getType() != ingredient.item.getType()) {
                        // Reset used items and try next recipe
                        for (CraftingHelper item : items) if (item != null)
                            item.timesUsed = 0;
                        continue recipes;
                    }
                    ingredient.timesUsed += 1;
                }
            }
        } else if (next instanceof ShapelessRecipe) {
            List<ItemStack> recipe_ingredients = ((ShapelessRecipe) next).getIngredientList();
            for (ItemStack required_item : recipe_ingredients) {
                boolean matched = items.stream().anyMatch(helper -> {
                    if (helper == null)
                        return false;
                    if (helper.item.getType() != required_item.getType())
                        return false;
                    if (helper.timesUsed >= helper.item.getAmount())
                        return false;
                    helper.timesUsed++;
                    return true;
                });
                if (!matched) {
                    for (CraftingHelper item : items) if (item != null)
                        item.timesUsed = 0;
                    continue recipes;
                }
            }
            crafted = true;
        } else {
            continue recipes;
        }
        // Ensure all items have actually been used as many times as they claim
        if (!items.stream().allMatch(helper -> helper == null || helper.timesUsed == helper.timesReferenced)) {
            for (CraftingHelper item : items) if (item != null)
                item.timesUsed = 0;
            continue recipes;
        }
        // Ensure no item underflowed
        for (CraftingHelper ingredient : items) {
            if (ingredient == null)
                continue;
            if (ingredient.timesUsed > ingredient.item.getAmount()) {
                throw new ApiError("invalid operation", String.format("attempted to use more %s than available", ingredient.item.getType()));
            }
        }
        // Ensure there's somewhere to put the resulting item
        if (!output.addItem(next.getResult()).isEmpty()) {
            throw new ApiError("invalid operation", "no space to store result");
        }
        if (ReplCraft.plugin.core_protect) {
            String player = client.getStructure().getPlayer().getName();
            ReplCraft.plugin.coreProtect.logContainerTransaction(player + " [API]", output.getLocation());
        }
        for (CraftingHelper ingredient : items) {
            if (ingredient == null)
                continue;
            ingredient.item.setAmount(ingredient.item.getAmount() - ingredient.timesUsed);
            if (ReplCraft.plugin.core_protect) {
                String player = client.getStructure().getPlayer().getName();
                ReplCraft.plugin.coreProtect.logContainerTransaction(player + " [API]", ingredient.location);
            }
        }
        crafted = true;
    }
    if (!crafted)
        throw new ApiError("invalid operation", "no matching recipe");
}
Also used : JSONArray(org.json.JSONArray) ArrayList(java.util.ArrayList) JSONObject(org.json.JSONObject) Block(org.bukkit.block.Block) ApiError(eelfloat.replcraft.exceptions.ApiError) Map(java.util.Map) Location(org.bukkit.Location)

Example 4 with ApiError

use of eelfloat.replcraft.exceptions.ApiError in project replcraft by LeeFlemingRepl.

the class GetInventory method execute.

@Override
public void execute(Client client, WsMessageContext ctx, JSONObject request, JSONObject response) throws ApiError {
    JSONArray items = new JSONArray();
    BlockState state = getBlock(client, request).getState();
    if (!(state instanceof Container)) {
        throw new ApiError("invalid operation", "block isn't a container");
    }
    ItemStack[] contents = ((Container) state).getInventory().getContents();
    for (int i = 0; i < contents.length; i++) {
        ItemStack item = contents[i];
        if (item == null)
            continue;
        JSONObject jsonitem = new JSONObject();
        jsonitem.put("index", i);
        jsonitem.put("type", item.getType().getKey());
        jsonitem.put("amount", item.getAmount());
        jsonitem.put("enchantments", item.getEnchantments().entrySet().stream().map(entry -> {
            JSONObject enchantment = new JSONObject();
            enchantment.put("id", entry.getKey().getKey());
            enchantment.put("lvl", entry.getValue().intValue());
            return enchantment;
        }).collect(Collectors.toList()));
        ItemMeta itemMeta = item.getItemMeta();
        if (itemMeta != null) {
            jsonitem.put("meta", itemMeta.serialize());
            if (itemMeta instanceof Damageable) {
                short maxDurability = item.getType().getMaxDurability();
                int damage = ((Damageable) itemMeta).getDamage();
                jsonitem.put("maxDurability", maxDurability);
                jsonitem.put("durability", maxDurability - damage);
            }
            if (itemMeta instanceof BookMeta) {
                jsonitem.put("pages", ((BookMeta) itemMeta).getPages());
                jsonitem.put("author", ((BookMeta) itemMeta).getAuthor());
                jsonitem.put("title", ((BookMeta) itemMeta).getTitle());
            }
        }
        items.put(jsonitem);
    }
    response.put("items", items);
}
Also used : Container(org.bukkit.block.Container) BlockState(org.bukkit.block.BlockState) JSONObject(org.json.JSONObject) Damageable(org.bukkit.inventory.meta.Damageable) JSONArray(org.json.JSONArray) ApiError(eelfloat.replcraft.exceptions.ApiError) ItemStack(org.bukkit.inventory.ItemStack) BookMeta(org.bukkit.inventory.meta.BookMeta) ItemMeta(org.bukkit.inventory.meta.ItemMeta)

Example 5 with ApiError

use of eelfloat.replcraft.exceptions.ApiError in project replcraft by LeeFlemingRepl.

the class GetSignText method execute.

@Override
public void execute(Client client, WsMessageContext ctx, JSONObject request, JSONObject response) throws ApiError {
    BlockState state = getBlock(client, request).getState();
    if (!(state instanceof Sign)) {
        throw new ApiError("invalid operation", "block is not a sign");
    }
    response.put("lines", ((Sign) state).getLines());
}
Also used : BlockState(org.bukkit.block.BlockState) Sign(org.bukkit.block.Sign) ApiError(eelfloat.replcraft.exceptions.ApiError)

Aggregations

ApiError (eelfloat.replcraft.exceptions.ApiError)13 Block (org.bukkit.block.Block)5 JSONObject (org.json.JSONObject)5 BlockState (org.bukkit.block.BlockState)4 OfflinePlayer (org.bukkit.OfflinePlayer)3 Player (org.bukkit.entity.Player)3 ItemStack (org.bukkit.inventory.ItemStack)3 JSONArray (org.json.JSONArray)3 InvalidStructure (eelfloat.replcraft.exceptions.InvalidStructure)2 Location (org.bukkit.Location)2 Container (org.bukkit.block.Container)2 Sign (org.bukkit.block.Sign)2 Inventory (org.bukkit.inventory.Inventory)2 JSONException (org.json.JSONException)2 ApiUtil.getBlock (eelfloat.replcraft.util.ApiUtil.getBlock)1 Claims (io.jsonwebtoken.Claims)1 JwtException (io.jsonwebtoken.JwtException)1 ArrayList (java.util.ArrayList)1 Map (java.util.Map)1 EconomyResponse (net.milkbowl.vault.economy.EconomyResponse)1