mirror of https://github.com/basinserver/basin/
249 lines
6.7 KiB
C
249 lines
6.7 KiB
C
/*
|
|
* craft.c
|
|
*
|
|
* Created on: Dec 26, 2016
|
|
* Author: root
|
|
*/
|
|
|
|
#include <basin/crafting.h>
|
|
#include <basin/network.h>
|
|
#include <basin/item.h>
|
|
#include <basin/block.h>
|
|
#include <basin/player.h>
|
|
#include <basin/game.h>
|
|
#include <avuna/string.h>
|
|
#include <avuna/json.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
void init_crafting() {
|
|
crafting_recipies = new_collection(128, 0);
|
|
char* jsf = xmalloc(4097);
|
|
size_t jsfs = 4096;
|
|
size_t jsr = 0;
|
|
int fd = open("crafting.json", O_RDONLY);
|
|
ssize_t r = 0;
|
|
while ((r = read(fd, jsf + jsr, jsfs - jsr)) > 0) {
|
|
jsr += r;
|
|
if (jsfs - jsr < 512) {
|
|
jsfs += 4096;
|
|
jsf = xrealloc(jsf, jsfs + 1);
|
|
}
|
|
}
|
|
jsf[jsr] = 0;
|
|
if (r < 0) {
|
|
printf("Error reading crafting recipes: %s\n", strerror(errno));
|
|
}
|
|
close(fd);
|
|
struct json_object json;
|
|
json_parse(&json, jsf);
|
|
for (size_t i = 0; i < json.child_count; i++) {
|
|
struct json_object* ur = json.children[i];
|
|
struct crafting_recipe* cr = xcalloc(sizeof(struct crafting_recipe));
|
|
struct json_object* tmp = json_get(ur, "shapeless");
|
|
if (tmp == NULL || (tmp->type != JSON_TRUE && tmp->type != JSON_FALSE)) goto cerr;
|
|
cr->shapeless = (uint8_t) tmp->type == JSON_TRUE;
|
|
tmp = json_get(ur, "width");
|
|
if ((tmp == NULL || tmp->type != JSON_NUMBER) && !cr->shapeless) goto cerr;
|
|
cr->width = cr->shapeless ? 0 : (uint8_t) tmp->data.number;
|
|
for (size_t x = 0; x < ur->child_count; x++) {
|
|
struct json_object* ir = ur->children[x];
|
|
if (streq_nocase(ir->name, "output")) {
|
|
tmp = json_get(ir, "item_id");
|
|
if (tmp == NULL || tmp->type != JSON_NUMBER) goto cerr;
|
|
cr->output.item = (int16_t) tmp->data.number;
|
|
tmp = json_get(ir, "item_damage");
|
|
if (tmp == NULL || tmp->type != JSON_NUMBER) goto cerr;
|
|
cr->output.damage = (int16_t) tmp->data.number;
|
|
tmp = json_get(ir, "item_count");
|
|
if (tmp == NULL || tmp->type != JSON_NUMBER) goto cerr;
|
|
cr->output.itemCount = (uint8_t) tmp->data.number;
|
|
cr->output.nbt = NULL;
|
|
} else if (startsWith_nocase(ir->name, "slot_")) {
|
|
uint8_t id = atoi(ir->name + 5);
|
|
if (id > 8) goto cerr;
|
|
cr->slot[id] = xmalloc(sizeof(struct slot));
|
|
tmp = json_get(ir, "item_id");
|
|
if (tmp == NULL || tmp->type != JSON_NUMBER) goto cerr;
|
|
cr->slot[id]->item = (int16_t) tmp->data.number;
|
|
tmp = json_get(ir, "item_damage");
|
|
if (tmp == NULL || tmp->type != JSON_NUMBER) goto cerr;
|
|
cr->slot[id]->damage = (int16_t) tmp->data.number;
|
|
cr->slot[id]->itemCount = 1;
|
|
cr->slot[id]->nbt = NULL;
|
|
}
|
|
}
|
|
add_collection(crafting_recipies, cr);
|
|
continue;
|
|
cerr: ;
|
|
printf("[WARNING] Error Loading Crafting Recipe \"%s\"! Skipped.\n", ur->name);
|
|
}
|
|
freeJSON(&json);
|
|
xfree(jsf);
|
|
}
|
|
|
|
void craftOnce(struct player* player, struct inventory* inv) {
|
|
int cs = inv->type == INVTYPE_PLAYERINVENTORY ? 4 : 9;
|
|
for (int i = 1; i <= cs; i++) {
|
|
struct slot* invi = getSlot(player, inv, i);
|
|
if (invi == NULL) continue;
|
|
if (--invi->itemCount <= 0) {
|
|
freeSlot(invi);
|
|
xfree(invi);
|
|
invi = NULL;
|
|
}
|
|
inv->slots[i] = invi;
|
|
}
|
|
onInventoryUpdate(player, inv, 1);
|
|
}
|
|
|
|
int craftAll(struct player* player, struct inventory* inv) {
|
|
int cs = inv->type == INVTYPE_PLAYERINVENTORY ? 4 : 9;
|
|
uint8_t ct = 64;
|
|
for (int i = 1; i <= cs; i++) {
|
|
struct slot* invi = getSlot(player, inv, i);
|
|
if (invi == NULL) continue;
|
|
if (invi->itemCount < ct) ct = invi->itemCount;
|
|
}
|
|
for (int i = 1; i <= cs; i++) {
|
|
struct slot* invi = getSlot(player, inv, i);
|
|
if (invi == NULL) continue;
|
|
invi->itemCount -= ct;
|
|
if (invi->itemCount <= 0) {
|
|
freeSlot(invi);
|
|
xfree(invi);
|
|
invi = NULL;
|
|
}
|
|
inv->slots[i] = invi;
|
|
}
|
|
return ct;
|
|
}
|
|
|
|
struct slot* getCraftResult(struct slot** slots, size_t slot_count) { // 012/345/678 or 01/23
|
|
struct slot** os = xmalloc(sizeof(struct slot*) * slot_count);
|
|
memcpy(os, slots, slot_count * sizeof(struct slot*));
|
|
if (slot_count == 4) {
|
|
if (os[0] == NULL && os[1] == NULL) {
|
|
os[0] = os[2];
|
|
os[1] = os[3];
|
|
os[2] = NULL;
|
|
os[3] = NULL;
|
|
}
|
|
if (os[0] == NULL && os[2] == NULL) {
|
|
os[0] = os[1];
|
|
os[2] = os[3];
|
|
os[1] = NULL;
|
|
os[3] = NULL;
|
|
}
|
|
} else if (slot_count == 9) {
|
|
if (!os[3] && !os[4] && !os[5]) {
|
|
memmove(os + 3, os + 6, 3 * sizeof(struct slot*));
|
|
memset(os + 6, 0, 3 * sizeof(struct slot*));
|
|
}
|
|
if (!os[0] && !os[1] && !os[2]) {
|
|
memmove(os, os + 3, 6 * sizeof(struct slot*));
|
|
memset(os + 6, 0, 3 * sizeof(struct slot*));
|
|
}
|
|
if (!os[0] && !os[3] && !os[6]) {
|
|
os[0] = os[1];
|
|
os[3] = os[4];
|
|
os[6] = os[7];
|
|
os[1] = os[2];
|
|
os[4] = os[5];
|
|
os[7] = os[8];
|
|
os[2] = NULL;
|
|
os[5] = NULL;
|
|
os[8] = NULL;
|
|
if (!os[0] && !os[3] && !os[6]) {
|
|
os[0] = os[1];
|
|
os[3] = os[4];
|
|
os[6] = os[7];
|
|
os[1] = NULL;
|
|
os[4] = NULL;
|
|
os[7] = NULL;
|
|
}
|
|
}
|
|
}
|
|
//for (int x = 0; x < slot_count; x++) {
|
|
// printf("post %i = %i\n", x, os[x] != NULL);
|
|
//}
|
|
for (size_t i = 0; i < crafting_recipies->size; i++) {
|
|
struct crafting_recipe* cr = (struct crafting_recipe*) crafting_recipies->data[i];
|
|
if (cr == NULL || (cr->width > 2 && slot_count <= 4) || (slot_count == 4 && (cr->slot[6] != NULL || cr->slot[7] != NULL || cr->slot[8] != NULL))) continue;
|
|
if (cr->shapeless) { // TODO: optimize
|
|
int gs = 1;
|
|
for (int ls = 0; ls <= slot_count; ls++) {
|
|
struct slot* iv = slots[ls];
|
|
if (iv == NULL) continue;
|
|
int m = 0;
|
|
for (int ri = 0; ri < 9; ri++) {
|
|
struct slot* cv = cr->slot[ri];
|
|
if (itemsStackable2(cv, iv)) {
|
|
m = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!m) {
|
|
gs = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (gs) for (int ri = 0; ri < 9; ri++) {
|
|
struct slot* cv = cr->slot[ri];
|
|
if (cv == NULL) continue;
|
|
int m = 0;
|
|
for (int ls = 1; ls <= 4; ls++) {
|
|
struct slot* iv = slots[ls];
|
|
if (itemsStackable2(cv, iv)) {
|
|
m = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!m) {
|
|
gs = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (gs) {
|
|
return &cr->output;
|
|
}
|
|
} else {
|
|
int gs = 1;
|
|
for (int x = 0; x < 3; x++) {
|
|
for (int y = 0; y < 3; y++) {
|
|
struct slot* cri = cr->slot[y * 3 + x];
|
|
struct slot* oi = (slot_count == 4 && (x > 1 || y > 1)) ? NULL : os[y * (slot_count == 4 ? 2 : 3) + x];
|
|
if (!itemsStackable2(cri, oi) && (cri != oi)) {
|
|
gs = 0;
|
|
goto ppbx;
|
|
}
|
|
}
|
|
}
|
|
ppbx: ;
|
|
if (!gs) {
|
|
gs = 1;
|
|
for (int x = 0; x < 3; x++) {
|
|
for (int y = 0; y < 3; y++) {
|
|
struct slot* cri = x >= cr->width ? NULL : cr->slot[y * 3 + ((cr->width - 1) - x)];
|
|
struct slot* oi = (slot_count == 4 && (x > 1 || y > 1)) ? NULL : os[y * (slot_count == 4 ? 2 : 3) + x];
|
|
if (!itemsStackable2(cri, oi) && (cri != oi)) {
|
|
gs = 0;
|
|
goto pbx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pbx: ;
|
|
if (gs) {
|
|
return &cr->output;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void add_crafting(struct crafting_recipe* recipe) {
|
|
add_collection(crafting_recipies, recipe);
|
|
}
|