lua: inventory library

This commit is contained in:
MihailRis 2024-02-12 13:56:46 +03:00
parent 617017d979
commit e16f7567b1
14 changed files with 257 additions and 44 deletions

42
src/items/Inventories.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "Inventories.h"
#include "../world/Level.h"
#include "../world/World.h"
Inventories::Inventories(Level& level) : level(level) {
}
Inventories::~Inventories() {
}
std::shared_ptr<Inventory> Inventories::create(size_t size) {
int64_t id = level.getWorld()->getNextInventoryId();
auto inv = std::make_shared<Inventory>(id, size);
store(inv);
return inv;
}
std::shared_ptr<Inventory> Inventories::createVirtual(size_t size) {
int64_t id;
do {
id = -std::max(1L, std::abs(random.rand64()));
} while (map.find(id) != map.end());
auto inv = std::make_shared<Inventory>(id, size);
store(inv);
return inv;
}
void Inventories::store(std::shared_ptr<Inventory> inv) {
map[inv->getId()] = inv;
}
std::shared_ptr<Inventory> Inventories::get(int64_t id) {
auto found = map.find(id);
if (found == map.end())
return nullptr;
return found->second;
}
const inventories_map& Inventories::getMap() const {
return map;
}

39
src/items/Inventories.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef ITEMS_INVENTORIES_H_
#define ITEMS_INVENTORIES_H_
#include <string>
#include <memory>
#include <unordered_map>
#include "Inventory.h"
#include "../maths/util.h"
class Level;
using inventories_map = std::unordered_map<int64_t, std::shared_ptr<Inventory>>;
/* Inventories runtime storage */
class Inventories {
Level& level;
inventories_map map;
PseudoRandom random;
public:
Inventories(Level& level);
~Inventories();
/* Create new inventory with new id */
std::shared_ptr<Inventory> create(size_t size);
/* Create runtime-only inventory (has negative id) */
std::shared_ptr<Inventory> createVirtual(size_t size);
/* Store inventory */
void store(std::shared_ptr<Inventory> inv);
/* Get inventory by id (works with both real and virtual)*/
std::shared_ptr<Inventory> get(int64_t id);
const inventories_map& getMap() const;
};
#endif // ITEMS_INVENTORIES_H_

View File

@ -2,7 +2,7 @@
#include "../content/ContentLUT.h"
Inventory::Inventory(uint id, size_t size) : id(id), slots(size) {
Inventory::Inventory(int64_t id, size_t size) : id(id), slots(size) {
}
ItemStack& Inventory::getSlot(size_t index) {

View File

@ -14,10 +14,10 @@ class ContentLUT;
class ContentIndices;
class Inventory : Serializable {
uint id;
int64_t id;
std::vector<ItemStack> slots;
public:
Inventory(uint id, size_t size);
Inventory(int64_t id, size_t size);
ItemStack& getSlot(size_t index);
size_t findEmptySlot(size_t begin=0, size_t end=-1) const;
@ -40,10 +40,14 @@ public:
static void convert(dynamic::Map* data, const ContentLUT* lut);
inline uint getId() const {
inline int64_t getId() const {
return id;
}
inline bool isVirtual() const {
return id < 0;
}
static const size_t npos;
};

View File

@ -94,6 +94,7 @@ void lua::LuaState::createFuncs() {
openlib("pack", packlib, 0);
openlib("world", worldlib, 0);
openlib("player", playerlib, 0);
openlib("inventory", inventorylib, 0);
openlib("item", itemlib, 0);
openlib("time", timelib, 0);
openlib("file", filelib, 0);

View File

@ -17,7 +17,9 @@
#include "../../voxels/Chunks.h"
#include "../../voxels/voxel.h"
#include "../../items/ItemDef.h"
#include "../../items/ItemStack.h"
#include "../../items/Inventory.h"
#include "../../items/Inventories.h"
#include "../../lighting/Lighting.h"
#include "../../logic/BlocksController.h"
#include "../../window/Window.h"
@ -229,7 +231,83 @@ static const luaL_Reg playerlib [] = {
{NULL, NULL}
};
/* == items-related functions == */
static void validate_itemid(lua_State* L, itemid_t id) {
if (id >= scripting::indices->countItemDefs()) {
luaL_error(L, "invalid item id");
}
}
/* == inventory library == */
static int l_inventory_get(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
lua::luaint slotid = lua_tointeger(L, 2);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
if (slotid < 0 || uint64_t(slotid) >= inv->size()) {
luaL_error(L, "slot index is out of range [0, inventory.size(invid)]");
}
ItemStack& item = inv->getSlot(slotid);
lua_pushinteger(L, item.getItemId());
lua_pushinteger(L, item.getCount());
return 2;
}
static int l_inventory_set(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
lua::luaint slotid = lua_tointeger(L, 2);
lua::luaint itemid = lua_tointeger(L, 3);
lua::luaint count = lua_tointeger(L, 4);
validate_itemid(L, itemid);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
if (slotid < 0 || uint64_t(slotid) >= inv->size()) {
luaL_error(L, "slot index is out of range [0, inventory.size(invid)]");
}
ItemStack& item = inv->getSlot(slotid);
item.set(ItemStack(itemid, count));
return 0;
}
static int l_inventory_size(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
lua_pushinteger(L, inv->size());
return 1;
}
static int l_inventory_add(lua_State* L) {
lua::luaint invid = lua_tointeger(L, 1);
lua::luaint itemid = lua_tointeger(L, 2);
lua::luaint count = lua_tointeger(L, 3);
validate_itemid(L, itemid);
auto inv = scripting::level->inventories->get(invid);
if (inv == nullptr) {
luaL_error(L, "inventory does not exists in runtime: %d", invid);
}
ItemStack item(itemid, count);
inv->move(item, scripting::indices);
lua_pushinteger(L, item.getCount());
return 1;
}
static const luaL_Reg inventorylib [] = {
{"get", l_inventory_get},
{"set", l_inventory_set},
{"size", l_inventory_size},
{"add", l_inventory_add},
{NULL, NULL}
};
/* == item library == */
static int l_item_name(lua_State* L) {
auto indices = scripting::content->getIndices();
lua::luaint id = lua_tointeger(L, 1);

View File

@ -9,7 +9,7 @@ class LuaState;
class Engine;
class Content;
class ContentPack;
struct ContentPack;
class ContentIndices;
class Level;
class Block;
@ -29,6 +29,7 @@ namespace scripting {
extern Level* level;
extern BlocksController* blocks;
/* Lua environment wrapper for automatic deletion */
class Environment {
int env;
public:
@ -64,13 +65,28 @@ namespace scripting {
void on_block_placed(Player* player, const Block* block, int x, int y, int z);
void on_block_broken(Player* player, const Block* block, int x, int y, int z);
bool on_block_interact(Player* player, const Block* block, int x, int y, int z);
/* Called on RMB click on block with the item selected
@return true if prevents default action */
bool on_item_use_on_block(Player* player, const ItemDef* item, int x, int y, int z);
/* Called on LMB click on block with the item selected
@return true if prevents default action */
bool on_item_break_block(Player* player, const ItemDef* item, int x, int y, int z);
/* Called on UI view show */
void on_ui_open(UiDocument* layout, Inventory* inventory);
/* Called on UI view close*/
void on_ui_close(UiDocument* layout, Inventory* inventory);
/* Load script associated with a Block */
void load_block_script(int env, std::string prefix, fs::path file, block_funcs_set& funcsset);
/* Load script associated with an Item */
void load_item_script(int env, std::string prefix, fs::path file, item_funcs_set& funcsset);
/* Load package-specific world script */
void load_world_script(int env, std::string prefix, fs::path file);
/* Load script associated with an UiDocument */
void load_layout_script(int env, std::string prefix, fs::path file, uidocscript& script);
/* Finalize lua state. Using scripting after will lead to Lua panic */
void close();
}

49
src/maths/util.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef MATHS_UTIL_H_
#define MATHS_UTIL_H_
#include <ctime>
#include <stdint.h>
class PseudoRandom {
unsigned short seed;
public:
PseudoRandom(){
seed = (unsigned short)time(0);
}
int rand(){
seed = (seed + 0x7ed5 + (seed << 6));
seed = (seed ^ 0xc23c ^ (seed >> 9));
seed = (seed + 0x1656 + (seed << 3));
seed = ((seed + 0xa264) ^ (seed << 4));
seed = (seed + 0xfd70 - (seed << 3));
seed = (seed ^ 0xba49 ^ (seed >> 8));
return (int)seed;
}
int32_t rand32() {
return (rand() << 16) | rand();
}
uint32_t randU32() {
return (rand() << 16) | rand();
}
int64_t rand64() {
uint64_t x = randU32();
uint64_t y = randU32();
return (x << 32ULL) | y;
}
void setSeed(int number){
seed = ((unsigned short)(number*23729) ^ (unsigned short)(number+16786));
rand();
}
void setSeed(int number1, int number2){
seed = (((unsigned short)(number1*23729) | (unsigned short)(number2%16786)) ^ (unsigned short)(number2*number1));
rand();
}
};
#endif // MATHS_UTIL_H_

View File

@ -18,10 +18,10 @@ const float FLIGHT_SPEED_MUL = 4.0f;
const float CHEAT_SPEED_MUL = 5.0f;
const float JUMP_FORCE = 8.0f;
Player::Player(glm::vec3 position, float speed) :
Player::Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv) :
speed(speed),
chosenSlot(0),
inventory(new Inventory(0, 40)),
inventory(inv),
camera(new Camera(position, glm::radians(90.0f))),
spCamera(new Camera(position, glm::radians(90.0f))),
tpCamera(new Camera(position, glm::radians(90.0f))),
@ -195,7 +195,6 @@ std::unique_ptr<dynamic::Map> Player::serialize() const {
}
void Player::deserialize(dynamic::Map *src) {
auto posarr = src->list("position");
glm::vec3& position = hitbox->position;
position.x = posarr->num(0);

View File

@ -48,7 +48,7 @@ public:
glm::vec2 cam = {};
Player(glm::vec3 position, float speed);
Player(glm::vec3 position, float speed, std::shared_ptr<Inventory> inv);
~Player();
void teleport(glm::vec3 position);

View File

@ -15,6 +15,7 @@
#include "../content/Content.h"
#include "../maths/voxmaths.h"
#include "../maths/util.h"
#include "../core_defs.h"
// TODO: do something with long conditions + move magic numbers to constants
@ -62,36 +63,6 @@ public:
}
};
class PseudoRandom {
unsigned short seed;
public:
PseudoRandom(){
seed = (unsigned short)time(0);
}
int rand(){
seed = (seed + 0x7ed5 + (seed << 6));
seed = (seed ^ 0xc23c ^ (seed >> 9));
seed = (seed + 0x1656 + (seed << 3));
seed = ((seed + 0xa264) ^ (seed << 4));
seed = (seed + 0xfd70 - (seed << 3));
seed = (seed ^ 0xba49 ^ (seed >> 8));
return (int)seed;
}
void setSeed(int number){
seed = ((unsigned short)(number*23729) ^ (unsigned short)(number+16786));
rand();
}
void setSeed(int number1,int number2){
seed = (((unsigned short)(number1*23729) | (unsigned short)(number2%16786)) ^ (unsigned short)(number2*number1));
rand();
}
};
float calc_height(fnl_state *noise, int cur_x, int cur_z){
float height = 0;

View File

@ -10,6 +10,7 @@
#include "../physics/PhysicsSolver.h"
#include "../objects/Player.h"
#include "../items/Inventory.h"
#include "../items/Inventories.h"
Level::Level(World* world, const Content* content, Player* player, EngineSettings& settings)
: world(world),
@ -30,6 +31,8 @@ Level::Level(World* world, const Content* content, Player* player, EngineSetting
events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type type, Chunk* chunk) {
this->chunksStorage->remove(chunk->x, chunk->z);
});
inventories = std::make_unique<Inventories>(*this);
}
Level::~Level(){

View File

@ -11,6 +11,7 @@ class World;
class Player;
class Chunks;
class Inventory;
class Inventories;
class LevelEvents;
class Lighting;
class PhysicsSolver;
@ -23,6 +24,7 @@ public:
Player* player;
Chunks* chunks;
ChunksStorage* chunksStorage;
std::unique_ptr<Inventories> inventories;
PhysicsSolver* physics;
Lighting* lighting;

View File

@ -13,6 +13,7 @@
#include "../voxels/ChunksStorage.h"
#include "../objects/Player.h"
#include "../window/Camera.h"
#include "../items/Inventories.h"
world_load_error::world_load_error(std::string message)
: std::runtime_error(message) {
@ -65,6 +66,7 @@ void World::write(Level* level) {
const float DEF_PLAYER_Y = 100.0f;
const float DEF_PLAYER_SPEED = 4.0f;
const int DEF_PLAYER_INVENTORY_SIZE = 40;
Level* World::create(std::string name,
fs::path directory,
@ -73,8 +75,12 @@ Level* World::create(std::string name,
const Content* content,
const std::vector<ContentPack>& packs) {
auto world = new World(name, directory, seed, settings, content, packs);
auto player = new Player(glm::vec3(0, DEF_PLAYER_Y, 0), DEF_PLAYER_SPEED);
return new Level(world, content, player, settings);
auto inv = std::make_shared<Inventory>(world->getNextInventoryId(), DEF_PLAYER_INVENTORY_SIZE);
auto player = new Player(
glm::vec3(0, DEF_PLAYER_Y, 0), DEF_PLAYER_SPEED, inv
);
auto level = new Level(world, content, player, settings);
level->inventories->store(player->getInventory());
}
Level* World::load(fs::path directory,
@ -90,10 +96,13 @@ Level* World::load(fs::path directory,
throw world_load_error("could not to find world.json");
}
auto player = new Player(glm::vec3(0, DEF_PLAYER_Y, 0), DEF_PLAYER_SPEED);
auto inv = std::make_shared<Inventory>(0, DEF_PLAYER_INVENTORY_SIZE);
auto player = new Player(
glm::vec3(0, DEF_PLAYER_Y, 0), DEF_PLAYER_SPEED, inv
);
auto level = new Level(world.get(), content, player, settings);
wfile->readPlayer(player);
level->inventories->store(player->getInventory());
world.release();
return level;
}