mirror of https://github.com/basinserver/basin/
151 lines
5.9 KiB
C
151 lines
5.9 KiB
C
#include <basin/smelting.h>
|
|
#include <basin/item.h>
|
|
#include <basin/globals.h>
|
|
#include <avuna/hash.h>
|
|
#include <avuna/list.h>
|
|
#include <avuna/json.h>
|
|
#include <avuna/string.h>
|
|
#include <avuna/pmem.h>
|
|
#include <avuna/util.h>
|
|
#include <avuna/log.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
struct hashmap* smelting_fuels; // key = id << 16 | data
|
|
|
|
struct list* smelting_recipes;
|
|
|
|
struct mempool* smelting_pool;
|
|
|
|
int16_t smelting_burnTime(struct slot* slot) {
|
|
if (slot == NULL || slot->item < 0) return 0;
|
|
uint32_t key = (uint32_t) slot->item << 16u | (uint32_t) slot->damage;
|
|
struct smelting_fuel* fuel = hashmap_getint(smelting_fuels, key);
|
|
if (fuel == NULL) {
|
|
key &= 0xFFFFlu << 16;
|
|
key |= 0xFFFF;
|
|
fuel = hashmap_getint(smelting_fuels, key);
|
|
}
|
|
if (fuel == NULL) {
|
|
return 0;
|
|
}
|
|
return fuel->burn_time;
|
|
}
|
|
|
|
struct slot* smelting_output(struct slot* input) {
|
|
// TODO: use a hashmap
|
|
if (input == NULL || input->item < 0) return 0;
|
|
pthread_rwlock_init(&smelting_fuels->rwlock);
|
|
for (size_t i = 0; i < smelting_recipes->count; i++) {
|
|
if (smelting_recipes->data[i] == NULL) continue;
|
|
struct smelting_recipe* sf = (struct smelting_recipe*) smelting_recipes->data[i];
|
|
if (slot_stackable_damage_ignore(input, &sf->input)) {
|
|
pthread_rwlock_unlock(&smelting_fuels->rwlock);
|
|
return &sf->output;
|
|
}
|
|
}
|
|
pthread_rwlock_unlock(&smelting_fuels->rwlock);
|
|
return 0;
|
|
}
|
|
|
|
void add_smelting_fuel(struct smelting_fuel* fuel) {
|
|
uint32_t key = (uint32_t) fuel->id << 16u | (uint32_t) fuel->damage;
|
|
hashmap_putint(smelting_fuels, key, fuel);
|
|
}
|
|
|
|
void add_smelting_recipe(struct smelting_recipe* recipe) {
|
|
list_append(smelting_recipes, recipe);
|
|
}
|
|
|
|
void init_smelting() {
|
|
smelting_pool = mempool_new();
|
|
smelting_fuels = hashmap_thread_new(64, smelting_pool);
|
|
smelting_recipes = list_thread_new(128, smelting_pool);
|
|
char* json_file = (char*) read_file_fully(smelting_pool, "smelting.json", NULL);
|
|
if (json_file == NULL) {
|
|
errlog(delog, "Error reading smelting data: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
struct json_object* json = NULL;
|
|
json_parse(smelting_pool, &json, json_file);
|
|
pprefree(smelting_pool, json_file);
|
|
struct json_object* fuels = json_get(json, "fuels");
|
|
if (fuels == NULL || fuels->type != JSON_OBJECT) goto format_error_json;
|
|
struct json_object* recipes = json_get(json, "recipes");
|
|
if (recipes == NULL || recipes->type != JSON_OBJECT) goto format_error_json;
|
|
ITER_LLIST(fuels->children_list, value) {
|
|
struct json_object* child_json = value;
|
|
struct json_object* id_json = json_get(child_json, "id");
|
|
if (id_json == NULL || id_json->type != JSON_NUMBER) {
|
|
goto fuel_format_error;
|
|
}
|
|
struct smelting_fuel* fuel = pcalloc(smelting_pool, sizeof(struct smelting_fuel));
|
|
fuel->id = (int16_t) id_json->data.number;
|
|
if (fuel->id <= 0) {
|
|
goto fuel_format_error;
|
|
}
|
|
struct json_object* damage_json = json_get(child_json, "damage");
|
|
if (damage_json == NULL || damage_json->type != JSON_NUMBER) {
|
|
goto fuel_format_error;
|
|
}
|
|
fuel->damage = (int16_t) damage_json->data.number;
|
|
struct json_object* burn_time_json = json_get(child_json, "burnTime");
|
|
if (burn_time_json == NULL || burn_time_json->type != JSON_NUMBER) {
|
|
goto fuel_format_error;
|
|
}
|
|
fuel->burn_time = (int16_t) burn_time_json->data.number;
|
|
add_smelting_fuel(fuel);
|
|
continue;
|
|
fuel_format_error:;
|
|
printf("[WARNING] Error Loading Smelting Fuel \"%s\"! Skipped.\n", child_json->name);
|
|
ITER_LLIST_END();
|
|
}
|
|
ITER_LLIST(recipes->children_list, value) {
|
|
struct json_object* child_json = value;
|
|
struct smelting_recipe* recipe = pcalloc(smelting_pool, sizeof(struct smelting_recipe));
|
|
struct json_object* input_json = json_get(child_json, "input_item");
|
|
if (input_json == NULL || input_json->type != JSON_NUMBER) {
|
|
goto format_error_recipe;
|
|
}
|
|
recipe->input.item = (int16_t) input_json->data.number;
|
|
if (recipe->input.item <= 0) goto format_error_recipe;
|
|
struct json_object* input_damage_json = json_get(child_json, "input_damage");
|
|
if (input_damage_json == NULL || input_damage_json->type != JSON_NUMBER) {
|
|
goto format_error_recipe;
|
|
}
|
|
recipe->input.damage = (int16_t) input_damage_json->data.number;
|
|
recipe->input.count = 1;
|
|
recipe->input.nbt = NULL;
|
|
struct json_object* output_json = json_get(child_json, "output_item");
|
|
if (output_json == NULL || output_json->type != JSON_NUMBER) {
|
|
goto format_error_recipe;
|
|
}
|
|
recipe->output.item = (int16_t) output_json->data.number;
|
|
if (recipe->output.item <= 0) {
|
|
goto format_error_recipe;
|
|
}
|
|
struct json_object* output_damage_json = json_get(child_json, "output_damage");
|
|
if (output_damage_json == NULL || output_damage_json->type != JSON_NUMBER) {
|
|
goto format_error_recipe;
|
|
}
|
|
recipe->output.damage = (int16_t) output_damage_json->data.number;
|
|
struct json_object* output_count_json = json_get(child_json, "output_count");
|
|
if (output_count_json == NULL || output_count_json->type != JSON_NUMBER) {
|
|
goto format_error_recipe;
|
|
}
|
|
recipe->output.count = (uint8_t) output_count_json->data.number;
|
|
recipe->output.nbt = NULL;
|
|
add_smelting_recipe(recipe);
|
|
continue;
|
|
format_error_recipe:;
|
|
printf("[WARNING] Error Loading Smelting Recipe \"%s\"! Skipped.\n", child_json->name);
|
|
ITER_LLIST_END();
|
|
}
|
|
pfree(json->pool);
|
|
return;
|
|
format_error_json: ;
|
|
pfree(json->pool);
|
|
printf("[ERROR] Critical Failure Loading 'smelting.json', No Fuels/Recipes Object!\n");
|
|
}
|