*
This commit is contained in:
392
Src/Server/Abstract.cpp
Normal file
392
Src/Server/Abstract.cpp
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
#include "Abstract.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace LV::Server {
|
||||||
|
|
||||||
|
NodeStateCondition nodestateExpression(const std::vector<NodestateEntry>& entries, const std::string& expression) {
|
||||||
|
// Скомпилировать выражение и просчитать таблицу CT
|
||||||
|
|
||||||
|
std::unordered_map<std::string, int> valueToInt;
|
||||||
|
for(const NodestateEntry& entry : entries) {
|
||||||
|
for(size_t index = 0; index < entry.ValueNames.size(); index++) {
|
||||||
|
valueToInt[entry.ValueNames[index]] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Парсинг токенов
|
||||||
|
enum class EnumTokenKind {
|
||||||
|
LParen, RParen,
|
||||||
|
Plus, Minus, Star, Slash, Percent,
|
||||||
|
Not, And, Or,
|
||||||
|
LT, LE, GT, GE, EQ, NE
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::variant<EnumTokenKind, std::string, int, uint16_t>> tokens;
|
||||||
|
ssize_t pos = 0;
|
||||||
|
auto skipWS = [&](){ while(pos<expression.size() && std::isspace((unsigned char) expression[pos])) ++pos; };
|
||||||
|
|
||||||
|
for(; pos < expression.size(); pos++) {
|
||||||
|
skipWS();
|
||||||
|
|
||||||
|
char c = expression[pos];
|
||||||
|
|
||||||
|
// Числа
|
||||||
|
if(std::isdigit(c)) {
|
||||||
|
ssize_t npos = pos;
|
||||||
|
for(; npos < expression.size() && std::isdigit(expression[npos]); npos++);
|
||||||
|
int value = std::stoi(expression.substr(pos, npos-pos));
|
||||||
|
tokens.push_back(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переменные
|
||||||
|
if(std::isalpha(c)) {
|
||||||
|
ssize_t npos = pos;
|
||||||
|
for(; npos < expression.size() && std::isalpha(expression[npos]); npos++);
|
||||||
|
std::string value = expression.substr(pos, npos-pos);
|
||||||
|
if(value == "true")
|
||||||
|
tokens.push_back(1);
|
||||||
|
else if(value == "false")
|
||||||
|
tokens.push_back(0);
|
||||||
|
else
|
||||||
|
tokens.push_back(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Двойные операторы
|
||||||
|
if(pos-1 < expression.size()) {
|
||||||
|
char n = expression[pos+1];
|
||||||
|
|
||||||
|
if(c == '<' && n == '=') {
|
||||||
|
tokens.push_back(EnumTokenKind::LE);
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
} else if(c == '>' && n == '=') {
|
||||||
|
tokens.push_back(EnumTokenKind::GE);
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
} else if(c == '=' && n == '=') {
|
||||||
|
tokens.push_back(EnumTokenKind::EQ);
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
} else if(c == '!' && n == '=') {
|
||||||
|
tokens.push_back(EnumTokenKind::NE);
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Операторы
|
||||||
|
switch(c) {
|
||||||
|
case '(': tokens.push_back(EnumTokenKind::LParen);
|
||||||
|
case ')': tokens.push_back(EnumTokenKind::RParen);
|
||||||
|
case '+': tokens.push_back(EnumTokenKind::Plus);
|
||||||
|
case '-': tokens.push_back(EnumTokenKind::Minus);
|
||||||
|
case '*': tokens.push_back(EnumTokenKind::Star);
|
||||||
|
case '/': tokens.push_back(EnumTokenKind::Slash);
|
||||||
|
case '%': tokens.push_back(EnumTokenKind::Percent);
|
||||||
|
case '!': tokens.push_back(EnumTokenKind::Not);
|
||||||
|
case '&': tokens.push_back(EnumTokenKind::And);
|
||||||
|
case '|': tokens.push_back(EnumTokenKind::Or);
|
||||||
|
case '<': tokens.push_back(EnumTokenKind::LT);
|
||||||
|
case '>': tokens.push_back(EnumTokenKind::GT);
|
||||||
|
}
|
||||||
|
|
||||||
|
MAKE_ERROR("Недопустимый символ: " << c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Разбор токенов
|
||||||
|
enum class Op {
|
||||||
|
Add, Sub, Mul, Div, Mod,
|
||||||
|
LT, LE, GT, GE, EQ, NE,
|
||||||
|
And, Or,
|
||||||
|
Pos, Neg, Not
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
struct Num { int v; };
|
||||||
|
struct Var { std::string name; };
|
||||||
|
struct Unary { Op op; uint16_t rhs; };
|
||||||
|
struct Binary { Op op; uint16_t lhs, rhs; };
|
||||||
|
std::variant<Num, Var, Unary, Binary> v;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Node> nodes;
|
||||||
|
|
||||||
|
for(size_t index = 0; index < tokens.size(); index++) {
|
||||||
|
auto &token = tokens[index];
|
||||||
|
|
||||||
|
if(std::string* value = std::get_if<std::string>(&token)) {
|
||||||
|
if(*value == "false") {
|
||||||
|
token = 0;
|
||||||
|
} else if(*value == "true") {
|
||||||
|
token = 1;
|
||||||
|
} else if(auto iter = valueToInt.find(*value); iter != valueToInt.end()) {
|
||||||
|
token = iter->second; // TODO:
|
||||||
|
} else {
|
||||||
|
Node node;
|
||||||
|
node.v = Node::Var(*value);
|
||||||
|
nodes.emplace_back(std::move(node));
|
||||||
|
assert(nodes.size() < std::pow(2, 16)-64);
|
||||||
|
token = uint16_t(nodes.size()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Рекурсивный разбор выражений в скобках
|
||||||
|
std::function<uint16_t(size_t pos)> lambdaParse = [&](size_t pos) -> uint16_t {
|
||||||
|
size_t end = tokens.size();
|
||||||
|
|
||||||
|
// Парсим выражения в скобках
|
||||||
|
for(size_t index = pos; index < tokens.size(); index++) {
|
||||||
|
if(EnumTokenKind* kind = std::get_if<EnumTokenKind>(&tokens[index])) {
|
||||||
|
if(*kind == EnumTokenKind::LParen) {
|
||||||
|
uint16_t node = lambdaParse(index+1);
|
||||||
|
tokens.insert(tokens.begin()+index, node);
|
||||||
|
tokens.erase(tokens.begin()+index+1, tokens.begin()+index+3);
|
||||||
|
end = tokens.size();
|
||||||
|
} else if(*kind == EnumTokenKind::RParen) {
|
||||||
|
end = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем унарные операции
|
||||||
|
for(ssize_t index = end; index >= pos; index--) {
|
||||||
|
if(EnumTokenKind *kind = std::get_if<EnumTokenKind>(&tokens[index])) {
|
||||||
|
if(*kind != EnumTokenKind::Not && *kind != EnumTokenKind::Plus && *kind != EnumTokenKind::Minus)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(index+1 >= end)
|
||||||
|
MAKE_ERROR("Отсутствует операнд");
|
||||||
|
|
||||||
|
auto rightToken = tokens[index+1];
|
||||||
|
if(std::holds_alternative<EnumTokenKind>(rightToken))
|
||||||
|
MAKE_ERROR("Недопустимый операнд");
|
||||||
|
|
||||||
|
if(int* value = std::get_if<int>(&rightToken)) {
|
||||||
|
if(*kind == EnumTokenKind::Not)
|
||||||
|
tokens[index] = *value ? 0 : 1;
|
||||||
|
else if(*kind == EnumTokenKind::Plus)
|
||||||
|
tokens[index] = +*value;
|
||||||
|
else if(*kind == EnumTokenKind::Minus)
|
||||||
|
tokens[index] = -*value;
|
||||||
|
|
||||||
|
} else if(uint16_t* value = std::get_if<uint16_t>(&rightToken)) {
|
||||||
|
Node node;
|
||||||
|
Node::Unary un;
|
||||||
|
un.rhs = *value;
|
||||||
|
|
||||||
|
if(*kind == EnumTokenKind::Not)
|
||||||
|
un.op = Op::Not;
|
||||||
|
else if(*kind == EnumTokenKind::Plus)
|
||||||
|
un.op = Op::Pos;
|
||||||
|
else if(*kind == EnumTokenKind::Minus)
|
||||||
|
un.op = Op::Neg;
|
||||||
|
|
||||||
|
node.v = un;
|
||||||
|
nodes.emplace_back(std::move(node));
|
||||||
|
assert(nodes.size() < std::pow(2, 16)-64);
|
||||||
|
tokens[index] = uint16_t(nodes.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
end--;
|
||||||
|
tokens.erase(tokens.begin()+index+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Бинарные в порядке приоритета
|
||||||
|
for(int priority = 0; priority < 6; priority++)
|
||||||
|
for(size_t index = pos; index < end; index++) {
|
||||||
|
EnumTokenKind *kind = std::get_if<EnumTokenKind>(&tokens[index]);
|
||||||
|
|
||||||
|
if(!kind)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(priority == 0 && *kind != EnumTokenKind::Star && *kind != EnumTokenKind::Slash && *kind != EnumTokenKind::Percent)
|
||||||
|
continue;
|
||||||
|
if(priority == 1 && *kind != EnumTokenKind::Plus && *kind != EnumTokenKind::Minus)
|
||||||
|
continue;
|
||||||
|
if(priority == 2 && *kind != EnumTokenKind::LT && *kind != EnumTokenKind::GT && *kind != EnumTokenKind::LE && *kind != EnumTokenKind::GE)
|
||||||
|
continue;
|
||||||
|
if(priority == 3 && *kind != EnumTokenKind::EQ && *kind != EnumTokenKind::NE)
|
||||||
|
continue;
|
||||||
|
if(priority == 4 && *kind != EnumTokenKind::And)
|
||||||
|
continue;
|
||||||
|
if(priority == 5 && *kind != EnumTokenKind::Or)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(index == pos)
|
||||||
|
MAKE_ERROR("Отсутствует операнд перед");
|
||||||
|
else if(index == end-1)
|
||||||
|
MAKE_ERROR("Отсутствует операнд после");
|
||||||
|
|
||||||
|
auto &leftToken = tokens[index-1];
|
||||||
|
auto &rightToken = tokens[index+1];
|
||||||
|
|
||||||
|
if(std::holds_alternative<EnumTokenKind>(leftToken))
|
||||||
|
MAKE_ERROR("Недопустимый операнд");
|
||||||
|
|
||||||
|
if(std::holds_alternative<EnumTokenKind>(rightToken))
|
||||||
|
MAKE_ERROR("Недопустимый операнд");
|
||||||
|
|
||||||
|
if(std::holds_alternative<int>(leftToken) && std::holds_alternative<int>(rightToken)) {
|
||||||
|
int value;
|
||||||
|
|
||||||
|
switch(*kind) {
|
||||||
|
case EnumTokenKind::Plus: value = std::get<int>(leftToken) + std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::Minus: value = std::get<int>(leftToken) - std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::Star: value = std::get<int>(leftToken) * std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::Slash: value = std::get<int>(leftToken) / std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::Percent: value = std::get<int>(leftToken) % std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::And: value = std::get<int>(leftToken) && std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::Or: value = std::get<int>(leftToken) || std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::LT: value = std::get<int>(leftToken) < std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::LE: value = std::get<int>(leftToken) <= std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::GT: value = std::get<int>(leftToken) > std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::GE: value = std::get<int>(leftToken) >= std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::EQ: value = std::get<int>(leftToken) == std::get<int>(rightToken); break;
|
||||||
|
case EnumTokenKind::NE: value = std::get<int>(leftToken) != std::get<int>(rightToken); break;
|
||||||
|
|
||||||
|
default: assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
leftToken = value;
|
||||||
|
} else {
|
||||||
|
Node node;
|
||||||
|
Node::Binary bin;
|
||||||
|
|
||||||
|
switch(*kind) {
|
||||||
|
case EnumTokenKind::Plus: bin.op = Op::Add; break;
|
||||||
|
case EnumTokenKind::Minus: bin.op = Op::Sub; break;
|
||||||
|
case EnumTokenKind::Star: bin.op = Op::Mul; break;
|
||||||
|
case EnumTokenKind::Slash: bin.op = Op::Div; break;
|
||||||
|
case EnumTokenKind::Percent: bin.op = Op::Mod; break;
|
||||||
|
case EnumTokenKind::And: bin.op = Op::And; break;
|
||||||
|
case EnumTokenKind::Or: bin.op = Op::Or; break;
|
||||||
|
case EnumTokenKind::LT: bin.op = Op::LT; break;
|
||||||
|
case EnumTokenKind::LE: bin.op = Op::LE; break;
|
||||||
|
case EnumTokenKind::GT: bin.op = Op::GT; break;
|
||||||
|
case EnumTokenKind::GE: bin.op = Op::GE; break;
|
||||||
|
case EnumTokenKind::EQ: bin.op = Op::EQ; break;
|
||||||
|
case EnumTokenKind::NE: bin.op = Op::NE; break;
|
||||||
|
|
||||||
|
default: assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(int* value = std::get_if<int>(&leftToken)) {
|
||||||
|
Node valueNode;
|
||||||
|
valueNode.v = Node::Num(*value);
|
||||||
|
nodes.emplace_back(std::move(valueNode));
|
||||||
|
assert(nodes.size() < std::pow(2, 16)-64);
|
||||||
|
bin.lhs = uint16_t(nodes.size()-1);
|
||||||
|
} else if(uint16_t* nodeId = std::get_if<uint16_t>(&leftToken)) {
|
||||||
|
bin.lhs = *nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(int* value = std::get_if<int>(&rightToken)) {
|
||||||
|
Node valueNode;
|
||||||
|
valueNode.v = Node::Num(*value);
|
||||||
|
nodes.emplace_back(std::move(valueNode));
|
||||||
|
assert(nodes.size() < std::pow(2, 16)-64);
|
||||||
|
bin.rhs = uint16_t(nodes.size()-1);
|
||||||
|
} else if(uint16_t* nodeId = std::get_if<uint16_t>(&rightToken)) {
|
||||||
|
bin.rhs = *nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes.emplace_back(std::move(node));
|
||||||
|
assert(nodes.size() < std::pow(2, 16)-64);
|
||||||
|
leftToken = uint16_t(nodes.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.erase(tokens.begin()+index, tokens.begin()+index+2);
|
||||||
|
end -= 2;
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tokens.size() != 1)
|
||||||
|
MAKE_ERROR("Выражение не корректно");
|
||||||
|
|
||||||
|
if(uint16_t* nodeId = std::get_if<uint16_t>(&tokens[0])) {
|
||||||
|
return *nodeId;
|
||||||
|
} else if(int* value = std::get_if<int>(&tokens[0])) {
|
||||||
|
Node node;
|
||||||
|
node.v = Node::Num(*value);
|
||||||
|
nodes.emplace_back(std::move(node));
|
||||||
|
assert(nodes.size() < std::pow(2, 16)-64);
|
||||||
|
return uint16_t(nodes.size()-1);
|
||||||
|
} else {
|
||||||
|
MAKE_ERROR("Выражение не корректно");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t nodeId = lambdaParse(0);
|
||||||
|
if(!tokens.empty())
|
||||||
|
MAKE_ERROR("Выражение не действительно");
|
||||||
|
|
||||||
|
std::unordered_map<std::string, int> vars;
|
||||||
|
std::function<int(uint16_t)> lambdaCalcNode = [&](uint16_t nodeId) -> int {
|
||||||
|
const Node& node = nodes[nodeId];
|
||||||
|
if(const Node::Num* value = std::get_if<Node::Num>(&node.v)) {
|
||||||
|
return value->v;
|
||||||
|
} else if(const Node::Var* value = std::get_if<Node::Var>(&node.v)) {
|
||||||
|
auto iter = vars.find(value->name);
|
||||||
|
if(iter == vars.end())
|
||||||
|
MAKE_ERROR("Неопознанное состояние");
|
||||||
|
|
||||||
|
return iter->second;
|
||||||
|
} else if(const Node::Unary* value = std::get_if<Node::Unary>(&node.v)) {
|
||||||
|
int rNodeValue = lambdaCalcNode(value->rhs);
|
||||||
|
switch(value->op) {
|
||||||
|
case Op::Not: return !rNodeValue;
|
||||||
|
case Op::Pos: return +rNodeValue;
|
||||||
|
case Op::Neg: return -rNodeValue;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
} else if(const Node::Binary* value = std::get_if<Node::Binary>(&node.v)) {
|
||||||
|
int lNodeValue = lambdaCalcNode(value->lhs);
|
||||||
|
int rNodeValue = lambdaCalcNode(value->rhs);
|
||||||
|
|
||||||
|
switch(value->op) {
|
||||||
|
case Op::Add: return lNodeValue+rNodeValue;
|
||||||
|
case Op::Sub: return lNodeValue-rNodeValue;
|
||||||
|
case Op::Mul: return lNodeValue*rNodeValue;
|
||||||
|
case Op::Div: return lNodeValue/rNodeValue;
|
||||||
|
case Op::Mod: return lNodeValue%rNodeValue;
|
||||||
|
case Op::LT: return lNodeValue<rNodeValue;
|
||||||
|
case Op::LE: return lNodeValue<=rNodeValue;
|
||||||
|
case Op::GT: return lNodeValue>rNodeValue;
|
||||||
|
case Op::GE: return lNodeValue>=rNodeValue;
|
||||||
|
case Op::EQ: return lNodeValue==rNodeValue;
|
||||||
|
case Op::NE: return lNodeValue!=rNodeValue;
|
||||||
|
case Op::And: return lNodeValue&&rNodeValue;
|
||||||
|
case Op::Or: return lNodeValue||rNodeValue;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeStateCondition ct;
|
||||||
|
for(int meta = 0; meta < 256; meta++) {
|
||||||
|
int meta_temp = meta;
|
||||||
|
|
||||||
|
for(size_t index = 0; index < entries.size(); index++) {
|
||||||
|
const auto& entry = entries[index];
|
||||||
|
|
||||||
|
vars[entry.Name] = meta_temp % entry.Variability;
|
||||||
|
meta_temp /= entry.Variability;
|
||||||
|
}
|
||||||
|
|
||||||
|
ct[meta] = (bool) lambdaCalcNode(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <boost/json.hpp>
|
#include <boost/json.hpp>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
|
||||||
namespace LV::Server {
|
namespace LV::Server {
|
||||||
@@ -167,133 +168,16 @@ struct NodestateEntry {
|
|||||||
std::vector<std::string> ValueNames;
|
std::vector<std::string> ValueNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NodestateExpression {
|
using NodeStateCondition = std::bitset<256>;
|
||||||
std::bitset<256> CT;
|
NodeStateCondition nodestateExpression(const std::vector<NodestateEntry>& entries, const std::string& expression);
|
||||||
|
|
||||||
NodestateExpression(std::vector<NodestateEntry>, const std::string& expression) {
|
struct ModelTransform {
|
||||||
// Скомпилировать выражение и просчитать таблицу CT
|
std::vector<BinModelId_t> Ids;
|
||||||
|
uint16_t Weight = 1;
|
||||||
// Парсинг токенов
|
bool UVLock = false;
|
||||||
enum class EnumTokenKind {
|
|
||||||
LParen, RParen,
|
|
||||||
Plus, Minus, Star, Slash, Percent,
|
|
||||||
Not, And, Or,
|
|
||||||
LT, LE, GT, GE, EQ, NE
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::variant<EnumTokenKind, std::string, int>> tokens;
|
|
||||||
ssize_t pos = 0;
|
|
||||||
auto skipWS = [&](){ while(pos<expression.size() && std::isspace((unsigned char) expression[pos])) ++pos; };
|
|
||||||
|
|
||||||
for(; pos < expression.size(); pos++) {
|
|
||||||
skipWS();
|
|
||||||
|
|
||||||
char c = expression[pos];
|
|
||||||
|
|
||||||
// Числа
|
|
||||||
if(std::isdigit(c)) {
|
|
||||||
ssize_t npos = pos;
|
|
||||||
for(; npos < expression.size() && std::isdigit(expression[npos]); npos++);
|
|
||||||
int value = std::stoi(expression.substr(pos, npos-pos));
|
|
||||||
tokens.push_back(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Переменные
|
|
||||||
if(std::isalpha(c)) {
|
|
||||||
ssize_t npos = pos;
|
|
||||||
for(; npos < expression.size() && std::isalpha(expression[npos]); npos++);
|
|
||||||
std::string value = expression.substr(pos, npos-pos);
|
|
||||||
if(value == "true")
|
|
||||||
tokens.push_back(1);
|
|
||||||
else if(value == "false")
|
|
||||||
tokens.push_back(0);
|
|
||||||
else
|
|
||||||
tokens.push_back(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Двойные операторы
|
|
||||||
if(pos-1 < expression.size()) {
|
|
||||||
char n = expression[pos+1];
|
|
||||||
|
|
||||||
if(c == '<' && n == '=') {
|
|
||||||
tokens.push_back(EnumTokenKind::LE);
|
|
||||||
pos++;
|
|
||||||
continue;
|
|
||||||
} else if(c == '>' && n == '=') {
|
|
||||||
tokens.push_back(EnumTokenKind::GE);
|
|
||||||
pos++;
|
|
||||||
continue;
|
|
||||||
} else if(c == '=' && n == '=') {
|
|
||||||
tokens.push_back(EnumTokenKind::EQ);
|
|
||||||
pos++;
|
|
||||||
continue;
|
|
||||||
} else if(c == '!' && n == '=') {
|
|
||||||
tokens.push_back(EnumTokenKind::NE);
|
|
||||||
pos++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Операторы
|
|
||||||
switch(c) {
|
|
||||||
case '(': tokens.push_back(EnumTokenKind::LParen);
|
|
||||||
case ')': tokens.push_back(EnumTokenKind::RParen);
|
|
||||||
case '+': tokens.push_back(EnumTokenKind::Plus);
|
|
||||||
case '-': tokens.push_back(EnumTokenKind::Minus);
|
|
||||||
case '*': tokens.push_back(EnumTokenKind::Star);
|
|
||||||
case '/': tokens.push_back(EnumTokenKind::Slash);
|
|
||||||
case '%': tokens.push_back(EnumTokenKind::Percent);
|
|
||||||
case '!': tokens.push_back(EnumTokenKind::Not);
|
|
||||||
case '&': tokens.push_back(EnumTokenKind::And);
|
|
||||||
case '|': tokens.push_back(EnumTokenKind::Or);
|
|
||||||
case '<': tokens.push_back(EnumTokenKind::LT);
|
|
||||||
case '>': tokens.push_back(EnumTokenKind::GT);
|
|
||||||
}
|
|
||||||
|
|
||||||
MAKE_ERROR("Недопустимый символ: " << c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Разбор токенов
|
|
||||||
enum class Op {
|
|
||||||
Add, Sub, Mul, Div, Mod,
|
|
||||||
LT, LE, GT, GE, EQ, NE,
|
|
||||||
And, Or,
|
|
||||||
Pos, Neg, Not
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Node> nodes;
|
|
||||||
|
|
||||||
struct Node {
|
|
||||||
struct Num { int v; };
|
|
||||||
struct Var { std::string name; };
|
|
||||||
struct Unary { Op op; uint16_t rhs; };
|
|
||||||
struct Binary { Op op; uint16_t lhs, rhs; };
|
|
||||||
std::variant<Num, Var, Unary, Binary> v;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Рекурсивный разбор выражений в скобках
|
|
||||||
std::function<uint16_t(const std::string_view&)> lambda = [&](const std::string_view& exp) -> uint16_t {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::string exp = TOS::Str::replace(expression, " ", "");
|
|
||||||
// exp = TOS::Str::replace(expression, "\0", "");
|
|
||||||
std::variant<std::string, Node> result = lambda(exp);
|
|
||||||
|
|
||||||
for(int meta = 0; meta < 256; meta++) {
|
|
||||||
CT[meta] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(uint8_t meta) {
|
|
||||||
return CT[meta];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DefNodeStates_t {
|
/*
|
||||||
/*
|
|
||||||
Указать модель, текстуры и поворот по конкретным осям.
|
Указать модель, текстуры и поворот по конкретным осям.
|
||||||
Может быть вариативность моделей относительно одного условия (случайность в зависимости от координат?)
|
Может быть вариативность моделей относительно одного условия (случайность в зависимости от координат?)
|
||||||
Допускается активация нескольких условий одновременно
|
Допускается активация нескольких условий одновременно
|
||||||
@@ -307,27 +191,23 @@ struct DefNodeStates_t {
|
|||||||
"": {"model": "node/grass", weight <вес влияющий на шанс отображения именно этой модели>}
|
"": {"model": "node/grass", weight <вес влияющий на шанс отображения именно этой модели>}
|
||||||
или просто
|
или просто
|
||||||
"model": "node/grass_node"
|
"model": "node/grass_node"
|
||||||
В условия добавить простые проверки !><=&|() in ['1', 2]
|
В условия добавить простые проверки !><=&|()
|
||||||
в задании параметров модели использовать формулы с применением состояний
|
в задании параметров модели использовать формулы с применением состояний
|
||||||
|
|
||||||
uvlock ? https://minecraft.wiki/w/Blockstates_definition/format
|
uvlock ? https://minecraft.wiki/w/Blockstates_definition/format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using DefNodestates_t = std::unordered_map<NodeStateCondition, std::vector<ModelTransform>>;
|
||||||
};
|
|
||||||
|
|
||||||
// Скомпилированный профиль ноды
|
// Скомпилированный профиль ноды
|
||||||
struct DefNode_t {
|
struct DefNode_t {
|
||||||
// Зарегистрированные состояния (мета)
|
// Зарегистрированные состояния (мета)
|
||||||
struct {
|
// Подгружается с файла assets/<modid>/nodestate/node/nodeId.json
|
||||||
// Подгружается с файла assets/<modid>/blockstate/node/nodeId.json
|
std::variant<DefNodestates_t, std::vector<ModelTransform>> StatesRouter;
|
||||||
DefNodeStates_t StateRouter;
|
|
||||||
|
|
||||||
} States;
|
|
||||||
|
|
||||||
// Параметры рендера
|
// Параметры рендера
|
||||||
struct {
|
struct {
|
||||||
bool hasHalfTransparency = false;
|
bool HasHalfTransparency = false;
|
||||||
} Render;
|
} Render;
|
||||||
|
|
||||||
// Параметры коллизии
|
// Параметры коллизии
|
||||||
@@ -345,9 +225,7 @@ struct DefNode_t {
|
|||||||
} Events;
|
} Events;
|
||||||
|
|
||||||
// Если нода умная, то для неё будет создаваться дополнительный более активный объект
|
// Если нода умная, то для неё будет создаваться дополнительный более активный объект
|
||||||
sol::protected_function NodeAdvancementFactory;
|
std::optional<sol::protected_function> NodeAdvancementFactory;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Entity {
|
class Entity {
|
||||||
|
|||||||
@@ -1596,6 +1596,62 @@ void GameServer::run() {
|
|||||||
LOG.info() << "Сервер завершил работу";
|
LOG.info() << "Сервер завершил работу";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefNode_t GameServer::createNodeProfileByLua(const sol::table& profile) {
|
||||||
|
DefNode_t result;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::variant<std::monostate, std::string, sol::table> parent = profile["parent"];
|
||||||
|
if(const sol::table* table = std::get_if<sol::table>(&parent)) {
|
||||||
|
result = createNodeProfileByLua(*table);
|
||||||
|
} else if(const std::string* key = std::get_if<std::string>(&parent)) {
|
||||||
|
auto regResult = TOS::Str::match(*key, "(?:([\\w\\d_]+):)?([\\w\\d_]+)");
|
||||||
|
if(!regResult)
|
||||||
|
MAKE_ERROR("Недействительный ключ в определении parent");
|
||||||
|
|
||||||
|
std::string realKey;
|
||||||
|
|
||||||
|
if(regResult->at(1)) {
|
||||||
|
realKey = *key;
|
||||||
|
} else {
|
||||||
|
realKey = "core:" + *regResult->at(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefNodeId_t parentId;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& list = Content.ContentKeyToId[(int) EnumDefContent::Node];
|
||||||
|
auto iter = list.find(realKey);
|
||||||
|
if(iter == list.end())
|
||||||
|
MAKE_ERROR("Идентификатор parent не найден");
|
||||||
|
|
||||||
|
parentId = iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = Content.ContentIdToDef_Node.at(parentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::optional<sol::table> nodestate = profile["nodestate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::optional<sol::table> render = profile["render"];
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::optional<sol::table> collision = profile["collision"];
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::optional<sol::table> events = profile["events"];
|
||||||
|
}
|
||||||
|
|
||||||
|
result.NodeAdvancementFactory = profile["node_advancement_factory"];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void GameServer::initLuaPre() {
|
void GameServer::initLuaPre() {
|
||||||
auto &lua = LuaMainState;
|
auto &lua = LuaMainState;
|
||||||
|
|
||||||
@@ -1608,9 +1664,6 @@ void GameServer::initLuaPre() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto &result = *result_o;
|
auto &result = *result_o;
|
||||||
|
|
||||||
DefNode_t node;
|
|
||||||
|
|
||||||
ResourceId_t sId;
|
ResourceId_t sId;
|
||||||
|
|
||||||
if(result[1])
|
if(result[1])
|
||||||
@@ -1618,7 +1671,7 @@ void GameServer::initLuaPre() {
|
|||||||
else
|
else
|
||||||
sId = Content.registerContent(CurrentModId+":"+*result[2], EnumDefContent::Node);
|
sId = Content.registerContent(CurrentModId+":"+*result[2], EnumDefContent::Node);
|
||||||
|
|
||||||
Content.ContentIdToDef_Node.insert({sId, std::move(node)});
|
Content.ContentIdToDef_Node.insert({sId, createNodeProfileByLua(profile)});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ struct ModRequest {
|
|||||||
|
|
||||||
struct ModInfo {
|
struct ModInfo {
|
||||||
std::string Id, Name, Description, Author;
|
std::string Id, Name, Description, Author;
|
||||||
|
std::vector<std::string> AlternativeIds;
|
||||||
std::array<uint32_t, 4> Version;
|
std::array<uint32_t, 4> Version;
|
||||||
std::vector<ModRequest> Dependencies, Optional;
|
std::vector<ModRequest> Dependencies, Optional;
|
||||||
float LoadPriority;
|
float LoadPriority;
|
||||||
@@ -301,10 +302,6 @@ class GameServer : public AsyncObject {
|
|||||||
// Идентификатор текущегго мода, находящевося в обработке
|
// Идентификатор текущегго мода, находящевося в обработке
|
||||||
std::string CurrentModId;
|
std::string CurrentModId;
|
||||||
|
|
||||||
struct {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameServer(asio::io_context &ioc, fs::path worldPath);
|
GameServer(asio::io_context &ioc, fs::path worldPath);
|
||||||
virtual ~GameServer();
|
virtual ~GameServer();
|
||||||
@@ -338,6 +335,8 @@ private:
|
|||||||
void prerun();
|
void prerun();
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
DefNode_t createNodeProfileByLua(const sol::table& profile);
|
||||||
|
|
||||||
|
|
||||||
void initLuaPre();
|
void initLuaPre();
|
||||||
void initLua();
|
void initLua();
|
||||||
|
|||||||
Reference in New Issue
Block a user