Segfault on usage of std::function from ticc_funcs.

This commit is contained in:
2025-03-27 17:44:21 -04:00
parent 3dd9d65964
commit f94c8b8e72
13 changed files with 239 additions and 188 deletions

View File

@@ -39,7 +39,7 @@ CPMAddPackage(
CPMAddPackage(
NAME jjx
URL https://git.redacted.cc/josh/jjx/archive/Prerelease-2.zip
URL https://git.redacted.cc/josh/jjx/archive/Release-1.zip
)
CPMAddPackage(

View File

@@ -4,8 +4,6 @@
"display-name": "Void",
"item-tooltip": "How did you even get this?",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFFFF",
"hardcoded-id": 65535,
"render": false
@@ -14,8 +12,6 @@
"mnemonic-id" : "air",
"display-name" : "Air",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFFFF",
"hardcoded-id": 0,
"render": false
@@ -24,8 +20,6 @@
"mnemonic-id" : "stone",
"display-name" : "Stone",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [112, 128, 144],
"pallet": [[112, 122, 148], [119, 136, 153], [121, 115, 138]]
},
@@ -33,8 +27,6 @@
"mnemonic-id" : "dirt",
"display-name" : "Dirt",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [210, 105, 30],
"pallet": [[210, 125, 30], [195, 105, 40], [210, 105, 30]]
},
@@ -42,32 +34,24 @@
"mnemonic-id" : "mud",
"display-name" : "Mud",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [139, 69, 19]
},
{
"mnemonic-id" : "limestone",
"display-name" : "Limestone",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [238, 232, 170]
},
{
"mnemonic-id" : "basalt",
"display-name" : "Basalt",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [105, 105, 105]
},
{
"mnemonic-id" : "cobblestone",
"display-name" : "Cobblestone",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [112, 128, 144],
"pallet": [[64, 64, 64], [92, 92, 92], [112, 128, 144], [119, 136, 153]],
"drops" : null
@@ -76,8 +60,6 @@
"mnemonic-id" : "red-moss",
"display-name" : "Red Moss",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#CC4444"
},
@@ -85,16 +67,12 @@
"mnemonic-id" : "brown-moss",
"display-name" : "Brown Moss",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#BB7755"
},
{
"mnemonic-id" : "green-moss",
"display-name" : "Green Moss",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF",
"pallet": []
},
@@ -102,35 +80,26 @@
"mnemonic-id" : "lava-moss",
"display-name" : "Lava Moss",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "granite",
"display-name" : "Granite",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF",
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
},
{
"mnemonic-id" : "marble",
"display-name" : "Marble",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "grass",
"display-name" : "Grass",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [124, 252, 0],
"pallet": [[126, 252, 5], [122, 238, 0], [124, 248, 12]]
},
@@ -138,24 +107,19 @@
"mnemonic-id" : "glowy-grass",
"display-name" : "Glowy Grass",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "vine",
"display-name" : "Vine",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": [32, 139, 34]
},
{
"mnemonic-id" : "sand",
"display-name" : "Sand",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"forced-ticc-func": "sand-grav",
"color": [238, 232, 170],
"pallet": [[238, 232, 170], [232, 238, 160], [218, 212, 175]]
},
@@ -163,96 +127,75 @@
"mnemonic-id" : "white-sand",
"display-name" : "White Sand",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"forced-ticc-func": "sand-grav",
"color": "#FFFFFF"
},
{
"mnemonic-id" : "red-sand",
"display-name" : "Red Sand",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"forced-ticc-func": "sand-grav",
"color": "#FFFFFF"
},
{
"mnemonic-id" : "black-sand",
"display-name" : "Black Sand",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"forced-ticc-func": "sand-grav",
"color": "#FFFFFF"
},
{
"mnemonic-id" : "sandstone",
"display-name" : "Sandstone",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "white-sandstone",
"display-name" : "White Sandstone",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "black-sandstone",
"display-name" : "Black Sandstone",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "ash",
"display-name" : "Ash",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "clay",
"display-name" : "Clay",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "silt",
"display-name" : "Silt",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "snow",
"display-name" : "Snow",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "ice",
"display-name" : "Ice",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF"
},
{
"mnemonic-id" : "slush",
"display-name" : "Slush",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF",
"pallet": []
},
@@ -261,8 +204,6 @@
"mnemonic-id" : "stone-brick",
"display-name" : "Gray Brick",
"solid": false,
"does-random-ticc": false,
"does-forced-ticc": false,
"color": "#FFFFFF",
"pallet": []
},
@@ -363,12 +304,8 @@
"mnemonic-id" : "water",
"display-name" : "Water",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": true,
"color": "#0000FF",
"pallet": [],
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
},
@@ -376,72 +313,49 @@
"mnemonic-id" : "blood",
"display-name" : "Blood",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": true,
"color": "#0000FF",
"pallet": [],
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
},
{
"mnemonic-id" : "sludge",
"display-name" : "Sludge",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": true,
"color": "#0000FF",
"pallet": [],
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
},
{
"mnemonic-id" : "lava",
"display-name" : "Lava",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": true,
"color": "#0000FF",
"pallet": [],
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
},
{
"mnemonic-id" : "ectoplasm",
"display-name" : "Ectoplasm",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": true,
"color": "#0000FF",
"pallet": [],
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
},
{
"mnemonic-id" : "milk",
"display-name" : "Milk",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": true,
"color": "#0000FF",
"pallet": [],
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
},
{
"mnemonic-id" : "honey",
"display-name" : "Honey",
"solid": true,
"does-random-ticc": false,
"does-forced-ticc": true,
"color": "#0000FF",
"pallet": [],
"random-ticc-func": "zzyyzz",
"forced-ticc-func": "zzyyzz",
"drops" : null
}
]

View File

@@ -1,7 +1,7 @@
#include <Client/CreditsWindow.hpp>
#include "ClientApp/CaveGameWindow.hpp"
//#include <bits/random.h>
#include <bits/random.h>
#include <Core/Explosion.hpp>
#include <Core/Loggers.hpp>
#include <Core/Player.hpp>
@@ -12,45 +12,13 @@
#include <Core/TileRegistry.hpp>
#include <JJX/JSON.hpp>
namespace CaveGame::ClientApp
{
namespace CaveGame::ClientApp {
using namespace CaveGame::Core;
using namespace CaveGame::Client;
void ReadRecipesAndRegister() {}
void ReadItemDataAndRegister() {
using namespace JJX;
std::string content = read_file("assets/data/items.json");
auto [data, parse_error] = json::parse(content);
if (data.type != json::value_type::array) {
// TODO: Error
return;
}
for (auto& entry : data.array.value()) {
Core::Item item;
auto entry_obj = json::object_val(entry);
item.mnemonic = entry_obj["mnemonic-id"];
item.display_name = entry_obj["display-name"];
Items().Register(item);
}
for (auto [name, item] : Items().GetItemMap()) {
std::cout << name << std::endl;
}
}
CaveGameWindow::CaveGameWindow(const std::string& title, int width, int height): ReWindow::OpenGLWindow(title, width, height, 2, 1)
{
Logs::Info("Parsing Tile Data.");

View File

@@ -82,6 +82,7 @@ namespace CaveGame::Core
int max_stack;
int value;
std::vector<std::string> tags;
std::vector<std::string> aliases;
std::optional<Color4> sprite_color;

View File

@@ -7,40 +7,39 @@
#include <vector>
#include <filesystem>
namespace CaveGame::Core
{
class ItemRegistry : public Singleton<ItemRegistry>
{
namespace CaveGame::Core {
/// This object contains the list of items in the game, which is pulled from json files at runtime.
class ItemRegistry : public Singleton<ItemRegistry> {
public:
void Register(Item data) {
Register(data.mnemonic, data);
}
bool Exists(const std::string& name) {
return registered_items.contains(name);
}
/// Adds an item into the game's list, using the mnemonic ID as a key for the lookup table.
/// @see Item.
void Register(const Item& data);
const Item& Get(const std::string& name) {
return registered_items.at(name);
}
/// @return True if an item with the given mnemonic string-id, or alias, exists in the item list.
bool Exists(const std::string& name);
std::unordered_map<std::string, Item> GetItemMap() { return registered_items;}
/// @return The Item associated with the given mnemonic string-id, or alias.
/// @throws std::runtime_error if no item with the given mnemonic is found.
const Item& Get(const std::string& name);
const Item& operator[](const std::string& name) { return Get(name);}
protected:
void Register(const std::string& mnemonic, const Item& data) {
registered_items.emplace(mnemonic, data);
}
/// @return The full list of items added to the game.
std::unordered_map<std::string, Item> GetItemMap();
/// @see ItemRegistry::Get()
const Item& operator[](const std::string& name);
protected:
std::unordered_map<std::string, Item> registered_items;
};
/// @return the global item registry singleton.
static ItemRegistry& Items() { return ItemRegistry::Instance();}
/// Reads, parses, and registers items from a given JSON file path.
bool LoadItemMetadata(const std::filesystem::path& path);
/// Reads, parses, and registers items from a pre-set list of JSON files.
bool LoadItemMetadata();
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include <Color4.hpp>
#include <Colors.hpp>
#include <JJX/JSON.hpp>
#include <map>
namespace JsonConversions {
using namespace JJX;
/// Parses an RGBA color structure from a json value, which may be one of the following:
/// \n * An array of 3 to 4 integers.
/// \n * A hexadecimal color-code string.
/// \n * A JSON object with 'r', 'g', 'b', and optional 'a' fields.
/// @return A Color4 structure.
Color4 parse_color(const json::value &v);
/// Parses a vector of strings from a json value, which may one string, or a JSON array of strings.
/// @return A vector containing the parsed strings, or an empty vector if the format is invalid.
std::vector<std::string> parse_string_list(const json::value& v);
}

View File

@@ -4,7 +4,7 @@
#include <Color4.hpp>
#include <Colors.hpp>
#include <Core/Data.hpp>
//#include <Core/Registry.hpp>
#include <map>
#include <functional>
#include <Core/Interfaces.hpp>
#include <J3ML/LinearAlgebra/Vector2i.hpp>
@@ -19,7 +19,13 @@ namespace CaveGame::Core {
struct Tile;
using ColorPallet = std::vector<Color4>;
//using TileTiccFunc = std::function<void(const Tile& data, ITileMap* world, int x, int y)>;
using TileTiccFunc = std::function<void(const Tile& data, ITileMap* world, int x, int y)>;
void SandGravTiccFunc(const Tile& data, ITileMap* world, int x, int y);
void LiquidSettleTiccFunc(const Tile& data, ITileMap* world, int x, int y);
static std::map<std::string, TileTiccFunc> ticc_funcs;
struct Tile {
@@ -33,6 +39,8 @@ namespace CaveGame::Core {
bool does_random_ticc = false;
bool does_forced_ticc = false;
Color4 color;
TileTiccFunc forced_ticc_func;
TileTiccFunc random_ticc_func;
};
/*
*

View File

@@ -77,8 +77,6 @@ namespace CaveGame::Core {
/// Convenient access to the tile registry.
static TileRegistry& Tiles() { return TileRegistry::Instance();}
Color4 parse_color(const JJX::json::value& v);
bool LoadTileMetadata(const std::filesystem::path& path);
bool LoadTileMetadata();

View File

@@ -1,15 +1,63 @@
#include <Core/ItemRegistry.hpp>
#include <Core/Macros.hpp>
#include <filesystem>
#include <JJX/JSON.hpp>
#include <Core/JsonConversions.hpp>
namespace CaveGame::Core
{
bool LoadItemMetadata(const std::filesystem::path &path) {
using namespace JJX;
std::string content = read_file(path);
auto [data, parse_error] = json::parse(content);
if (data.type != json::value_type::array) {
// TODO: Error
return false;
}
for (auto& entry : data.as_array()) {
auto entry_obj = entry.as_object();
Core::Item item;
item.mnemonic = entry_obj["mnemonic-id"].string.value_or("");
item.display_name = entry_obj["display-name"].string.value_or("");
if (entry_obj.contains("tags"))
item.tags = JsonConversions::parse_string_list(entry_obj["tags"]);
Items().Register(item);
}
for (auto [name, item] : Items().GetItemMap()) {
std::cout << name << std::endl;
}
return true;
}
bool LoadItemMetadata() {
LoadItemMetadata("assets/data/items.json");
if (!LoadItemMetadata("assets/data/items.json")) return false;
return true;
}
void ItemRegistry::Register(const Item& data) {
registered_items.emplace(data.mnemonic, data);
}
bool ItemRegistry::Exists(const std::string &name) {
return registered_items.contains(name);
}
const Item &ItemRegistry::Get(const std::string &name) {
return registered_items.at(name);
}
std::unordered_map<std::string, Item> ItemRegistry::GetItemMap() { return registered_items;}
const Item &ItemRegistry::operator[](const std::string &name) { return Get(name);}
}

View File

@@ -0,0 +1,46 @@
#include <Core/JsonConversions.hpp>
Color4 JsonConversions::parse_color(const JJX::json::value &v) {
if (v.type == json::value_type::string)
return Color4::FromHex(v.string.value());
else if (v.type == json::value_type::array) {
auto color_array = v.as_array();
int r = color_array[0].number.value();
int g = color_array[1].number.value();
int b = color_array[2].number.value();
int a = 255;
if (color_array.value::array.value().size() == 4)
a = color_array[3].number.value();
return Color4(r, g, b, a);
} else if (v.type == json::value_type::object) {
auto color_obj = v.operator std::map<std::string, json::value>();
int r = color_obj["r"].number.value();
int g = color_obj["g"].number.value();
int b = color_obj["b"].number.value();
int a = 255;
if (color_obj.contains("a"))
a = color_obj["a"].number.value();
return Color4(r, g, b, a);
}
return Colors::Transparent;
}
std::vector<std::string> JsonConversions::parse_string_list(const JJX::json::value &v) {
// TODO: Log an error if the json value is an invalid type.
if (v.type == json::value_type::string) {
return {v.string.value()};
}else if (v.type == json::value_type::array) {
std::vector<std::string> retval;
for (auto& token : v.array.value())
retval.push_back(token.string.value());
return retval;
}
return {};
}

View File

@@ -2,6 +2,7 @@
#include <Core/Tile.hpp>
#include <array>
#include "Core/Item.hpp"
#include "Core/TileRegistry.hpp"
namespace CaveGame::Core {
@@ -280,9 +281,27 @@ namespace CaveGame::Core {
}
WaterTile::WaterTile() : LiquidTile() {}
WaterTile::WaterTile(TileID id, const std::string &name, const Color4 &color) : LiquidTile(id, name, color) {}*/
void SandGravTiccFunc(const Tile &data, ITileMap *world, int x, int y) {
static TileID air = TileRegistry()["air"].numeric_id;
static TileID water = TileRegistry()["water"].numeric_id;
static TileID sand = data.numeric_id;
TileID below = world->GetTile(x, y + 1);
if (below == air || below == water) {
world->SwapTile(x, y, x, y+1);
} else if (below == sand && world->GetTile(x, y + 2) == sand) {
bool rng_roll = rand() % 2 == 0;
if (world->GetTile(rng_roll ? (x + 1) : (x - 1), y) == air)
world->SwapTile(x, y, rng_roll ? (x + 1) : (x - 1), y);
}
}
void LiquidSettleTiccFunc(const Tile &data, ITileMap *world, int x, int y) {
}
}

View File

@@ -4,6 +4,8 @@
#include <Core/Item.hpp>
#include <Core/ItemRegistry.hpp>
#include <Core/Macros.hpp>
#include <Core/JsonConversions.hpp>
#include <JJX/JSON.hpp>
namespace CaveGame::Core
{
@@ -88,36 +90,73 @@ namespace CaveGame::Core
bool TileRegistry::Exists(u16 id) { return id_to_name_mapping.contains(id); }
bool LoadTileMetadata(const std::filesystem::path &path) {
ticc_funcs.insert({"sand-grav", SandGravTiccFunc});
using namespace JJX;
std::string content = read_file(path);
auto [data, parse_error] = json::parse(content);
if (data.type == json::value_type::array) {
auto arr_data = json::array_val(data);
for (auto& t : arr_data.array.value()) {
for (auto& te : data.as_array()) {
Core::Tile tile;
Core::Item tile_item;
auto tile_meta_json = json::object_val(t);
json::object tile_entry = te.as_object();
if (tile_meta_json.object->contains("hardcoded-id"))
tile.assigned_numeric_id = tile_meta_json["hardcoded-id"].number;
if (tile_entry.contains("hardcoded-id"))
tile.assigned_numeric_id = tile_entry["hardcoded-id"].number;
tile.mnemonic_id = tile_meta_json["mnemonic-id"];
tile.display_name = tile_meta_json["display-name"];
tile.mnemonic_id = tile_entry.at("mnemonic-id").string.value();
tile.display_name = tile_entry.at("display-name").string.value();
tile_item.mnemonic = std::format("{}-tile", tile.mnemonic_id);
tile_item.display_name = tile.display_name;
tile.color = parse_color(tile_meta_json["color"]);
tile.color = JsonConversions::parse_color(tile_entry["color"]);
if (tile_meta_json.object->contains("pallet") && tile_meta_json["pallet"].array->size() > 0) {
std::string ftfkey = "forced-ticc-func";
std::string rtfkey = "random-ticc-func";
// Retrieve and evaluate the force ticc function ID. Assign to tile if valid.
tile.does_forced_ticc = false;
if (tile_entry.contains(ftfkey)
&& tile_entry[ftfkey].type == json::value_type::string
&& !tile_entry[ftfkey].string.value().empty())
{
std::string ticc_func_name = tile_entry[ftfkey].string.value();
if (!ticc_funcs.contains(ticc_func_name)) {
std::cerr << "No Tile Ticc Function with ID " << ticc_func_name << " found!" << std::endl;
} else {
tile.does_forced_ticc = true;
tile.forced_ticc_func = ticc_funcs.at(ticc_func_name);
}
}
// Retrieve and evaluate the random ticc function ID. Assign to tile if valid.
tile.does_random_ticc = false;
if (tile_entry.contains(rtfkey)
&& tile_entry[rtfkey].type == json::value_type::string
&& !tile_entry[rtfkey].string.value().empty())
{
std::string ticc_func_name = tile_entry[rtfkey].string.value();
if (!ticc_funcs.contains(ticc_func_name)) {
std::cerr << "No Tile Ticc Function with ID " << ticc_func_name << " found!" << std::endl;
} else {
tile.does_random_ticc = true;
tile.random_ticc_func = ticc_funcs.at(ticc_func_name);
}
}
if (tile_entry.contains("pallet") && tile_entry["pallet"].array->size() > 0) {
std::vector<Color4> pallet;
auto pallet_meta = json::array_val(tile_meta_json["pallet"]);
auto pallet_meta = tile_entry["pallet"].as_array();
for (auto& c : pallet_meta.array.value())
pallet.push_back(parse_color(c));
for (auto& c : pallet_meta)
pallet.push_back(JsonConversions::parse_color(c));
tile.pallet = pallet;
}
@@ -129,28 +168,8 @@ namespace CaveGame::Core
}
bool LoadTileMetadata() {
LoadTileMetadata("assets/data/tiles.json");
if (!LoadTileMetadata("assets/data/tiles.json")) return false;
return true;
}
Color4 parse_color(const JJX::json::value &v) {
if (v.type == JJX::json::value_type::string)
return Color4::FromHex(v.string.value());
else if (v.type == JJX::json::value_type::array)
{
auto color_array = JJX::json::array_val(v);
int r = color_array[0].number.value();
int g = color_array[1].number.value();
int b = color_array[2].number.value();
int a = 255;
if (color_array.array.value().size() == 4)
a = color_array[3].number.value();
return Color4(r, g, b, a);
}
return Colors::Transparent;
}
}

View File

@@ -478,7 +478,7 @@ namespace CaveGame::Core {
if (!chunk->HasUpdate())
return;
Tile* tile;
Tile tile;
chunk->SwapTileUpdateBuffers();
for (int x = 0; x < Core::Chunk::ChunkSize; x++) {
for (int y = 0; y < Core::Chunk::ChunkSize; y++) {
@@ -489,6 +489,14 @@ namespace CaveGame::Core {
continue;
TileID at = chunk->GetTile(x, y);
if (at == 0)
continue;
tile = Tiles().GetByNumericID(at);
if (tile.does_forced_ticc)
tile.forced_ticc_func(tile, this, wx, wy);
//if (at == TileID::AIR)
// continue;