#include "APIHelp.h" #include "BaseAPI.h" #include "McAPI.h" #include "BlockAPI.h" #include "ContainerAPI.h" #include "EntityAPI.h" #include "BlockEntityAPI.h" #include "NbtAPI.h" #include "NativeAPI.h" #include #include #include #include #include #include #include //////////////////// Class Definition //////////////////// ClassDefine BlockClassBuilder = defineClass("LLSE_Block") .constructor(nullptr) .instanceFunction("asPointer", &BlockClass::asPointer) .instanceProperty("name", &BlockClass::getName) .instanceProperty("type", &BlockClass::getType) .instanceProperty("id", &BlockClass::getId) .instanceProperty("pos", &BlockClass::getPos) .instanceProperty("tileData", &BlockClass::getTileData) .instanceFunction("setNbt", &BlockClass::setNbt) .instanceFunction("getNbt", &BlockClass::getNbt) .instanceFunction("getBlockState", &BlockClass::getBlockState) .instanceFunction("hasContainer", &BlockClass::hasContainer) .instanceFunction("getContainer", &BlockClass::getContainer) .instanceFunction("hasBlockEntity", &BlockClass::hasBlockEntity) .instanceFunction("getBlockEntity", &BlockClass::getBlockEntity) .instanceFunction("removeBlockEntity", &BlockClass::removeBlockEntity) .instanceFunction("destroy", &BlockClass::destroyBlock) // For Compatibility .instanceFunction("setTag", &BlockClass::setNbt) .instanceFunction("getTag", &BlockClass::getNbt) .build(); //////////////////// Classes //////////////////// BlockClass::BlockClass(Block const* p) : ScriptClass(ScriptClass::ConstructFromCpp{}), block(const_cast(p)) { preloadData({0, 0, 0}, -1); } BlockClass::BlockClass(Block const* p, BlockPos bp, int dim) : ScriptClass(ScriptClass::ConstructFromCpp{}), block(const_cast(p)) { preloadData(bp, dim); } // generating function Local BlockClass::newBlock(Block const* p, BlockPos const* pos, int dim) { auto newp = new BlockClass(p, *pos, dim); return newp->getScriptObject(); } Local BlockClass::newBlock(BlockPos const* pos, int dim) { return BlockClass::newBlock(Level::getBlock(const_cast(pos), dim), pos, dim); } Local BlockClass::newBlock(const BlockPos& pos, int dim) { return newBlock((BlockPos*)&pos, dim); } Local BlockClass::newBlock(Block const* p, BlockPos const* pos, BlockSource const* bs) { auto newp = new BlockClass(p, *pos, bs->getDimensionId()); return newp->getScriptObject(); } Local BlockClass::newBlock(IntVec4 pos) { BlockPos bp = {pos.x, pos.y, pos.z}; return BlockClass::newBlock(Level::getBlock(bp, pos.dim), &bp, pos.dim); } Local BlockClass::newBlock(BlockInstance block) { BlockPos bp = block.getPosition(); return BlockClass::newBlock(block.getBlock(), &bp, block.getDimensionId()); } Block* BlockClass::extract(Local v) { if (EngineScope::currentEngine()->isInstanceOf(v)) return EngineScope::currentEngine()->getNativeInstance(v)->get(); else return nullptr; } // member function void BlockClass::preloadData(BlockPos bp, int dim) { name = block->getTypeName(); // TODO type = block->getTypeName(); id = block->getId(); pos = {bp.x, bp.y, bp.z, dim}; } Local BlockClass::getName() { try { // preloaded return String::newString(name); } CATCH("Fail in getBlockName!"); } Local BlockClass::getType() { try { // preloaded return String::newString(type); } CATCH("Fail in getBlockType!"); } Local BlockClass::getId() { try { // preloaded return Number::newNumber(id); } CATCH("Fail in getBlockId!"); } Local BlockClass::getPos() { try { // preloaded return IntPos::newPos(pos); } CATCH("Fail in getBlockPos!"); } Local BlockClass::getTileData() { try { // preloaded return Number::newNumber(block->getTileData()); } CATCH("Fail in getTileData!"); } Local BlockClass::asPointer(const Arguments& args) { try { return NativePointer::newNativePointer(block); } CATCH("Fail in asPointer!"); } Local BlockClass::destroyBlock(const Arguments& args) { CHECK_ARGS_COUNT(args, 1); CHECK_ARG_TYPE(args[0], ValueKind::kBoolean); try { // same as `Level::getBlockInstance(pos.getBlockPos(), pos.dim).breakNaturally()` when drop return Boolean::newBoolean(Global->destroyBlock(*Level::getBlockSource(pos.dim), pos.getBlockPos(), args[0].asBoolean().value())); } CATCH("Fail in destroyBlock!"); } Local BlockClass::getNbt(const Arguments& args) { try { return NbtCompoundClass::pack(std::move(block->getNbt())); } CATCH("Fail in getNbt!"); } Local BlockClass::setNbt(const Arguments& args) { CHECK_ARGS_COUNT(args, 1); try { auto nbt = NbtCompoundClass::extract(args[0]); if (!nbt) return Local(); // Null // update Pre Data Level::setBlock(pos.getBlockPos(), pos.dim, (CompoundTag*)nbt); preloadData(pos.getBlockPos(), pos.getDimensionId()); return Boolean::newBoolean(true); } CATCH("Fail in setNbt!") } Local BlockClass::getBlockState(const Arguments& args) { try { auto list = block->getNbt(); try { return Tag2Value((Tag*)list->get("states"), true); } catch (...) { return Array::newArray(); } } catch (const std::out_of_range& e) { return Object::newObject(); } CATCH("Fail in getBlockState!") } Local BlockClass::hasContainer(const Arguments& args) { try { auto bl = Level::getBlockInstance({pos.x, pos.y, pos.z}, pos.dim); return Boolean::newBoolean(bl.hasContainer()); } CATCH("Fail in hasContainer!"); } Local BlockClass::getContainer(const Arguments& args) { try { Container* container = Level::getBlockInstance({pos.x, pos.y, pos.z}, pos.dim).getContainer(); return container ? ContainerClass::newContainer(container) : Local(); } CATCH("Fail in getContainer!"); } Local BlockClass::hasBlockEntity(const Arguments& args) { try { return Boolean::newBoolean(block->hasBlockEntity()); } CATCH("Fail in hasBlockEntity!"); } Local BlockClass::getBlockEntity(const Arguments& args) { try { BlockInstance bl = Level::getBlockInstance(pos.getBlockPos(), pos.dim); BlockActor* be = bl.getBlockEntity(); return be ? BlockEntityClass::newBlockEntity(be, pos.dim) : Local(); } CATCH("Fail in getBlockEntity!"); } Local BlockClass::removeBlockEntity(const Arguments& args) { try { BlockSource* bs = Level::getBlockSource(pos.dim); bs->removeBlockEntity(pos.getBlockPos()); //==========??? return Boolean::newBoolean(true); } CATCH("Fail in removeBlockEntity!"); } // public API Local McClass::getBlock(const Arguments& args) { CHECK_ARGS_COUNT(args, 1); try { IntVec4 pos; if (args.size() == 1) { // IntPos if (IsInstanceOf(args[0])) { // IntPos IntPos* posObj = IntPos::extractPos(args[0]); if (posObj->dim < 0) return Boolean::newBoolean(false); else { pos = *posObj; } } else if (IsInstanceOf(args[0])) { // FloatPos FloatPos* posObj = FloatPos::extractPos(args[0]); if (posObj->dim < 0) return Boolean::newBoolean(false); else { pos = posObj->toIntVec4(); } } else { LOG_WRONG_ARG_TYPE(); return Local(); } } else if (args.size() == 4) { // Number Pos CHECK_ARG_TYPE(args[0], ValueKind::kNumber); CHECK_ARG_TYPE(args[1], ValueKind::kNumber); CHECK_ARG_TYPE(args[2], ValueKind::kNumber); CHECK_ARG_TYPE(args[3], ValueKind::kNumber); pos = {args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()}; } else { LOG_WRONG_ARGS_COUNT(); return Local(); } auto block = Level::getBlockEx(pos.getBlockPos(), pos.dim); if (!block) { // LOG_WRONG_ARG_TYPE(); return Local(); } BlockPos bp{pos.x, pos.y, pos.z}; return BlockClass::newBlock(block, &bp, pos.dim); } CATCH("Fail in GetBlock!") } Local McClass::setBlock(const Arguments& args) { CHECK_ARGS_COUNT(args, 2); try { IntVec4 pos; Local block; unsigned short tileData = 0; if (args.size() == 2 || args.size() == 3) { if (args.size() == 3) { CHECK_ARG_TYPE(args[1], ValueKind::kString); CHECK_ARG_TYPE(args[2], ValueKind::kNumber); tileData = args[2].toInt(); } if (IsInstanceOf(args[0])) { // IntPos IntPos* posObj = IntPos::extractPos(args[0]); if (posObj->dim < 0) return Boolean::newBoolean(false); else { pos = *posObj; block = args[1]; } } else if (IsInstanceOf(args[0])) { // FloatPos FloatPos* posObj = FloatPos::extractPos(args[0]); if (posObj->dim < 0) return Boolean::newBoolean(false); else { pos = posObj->toIntVec4(); block = args[1]; } } else { LOG_WRONG_ARG_TYPE(); return Local(); } } else if (args.size() == 5 || args.size() == 6) { // Number Pos CHECK_ARG_TYPE(args[0], ValueKind::kNumber); CHECK_ARG_TYPE(args[1], ValueKind::kNumber); CHECK_ARG_TYPE(args[2], ValueKind::kNumber); CHECK_ARG_TYPE(args[3], ValueKind::kNumber); pos = {args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()}; block = args[4]; if (args.size() == 6) { CHECK_ARG_TYPE(args[4], ValueKind::kString); CHECK_ARG_TYPE(args[5], ValueKind::kNumber); tileData = args[5].toInt(); } } else { LOG_WRONG_ARGS_COUNT(); return Local(); } if (block.isString()) { // block name return Boolean::newBoolean(Level::setBlock(pos.getBlockPos(), pos.dim, block.toStr(), tileData)); } else if (IsInstanceOf(block)) { // Nbt Tag* nbt = NbtCompoundClass::extract(block); return Boolean::newBoolean(Level::setBlock(pos.getBlockPos(), pos.dim, (CompoundTag*)nbt)); } else { // other block object Block* bl = BlockClass::extract(block); if (!bl) { LOG_WRONG_ARG_TYPE(); return Local(); } return Boolean::newBoolean(Level::setBlock(pos.getBlockPos(), pos.dim, bl)); } } CATCH("Fail in SetBlock!") } Local McClass::spawnParticle(const Arguments& args) { CHECK_ARGS_COUNT(args, 2) try { FloatVec4 pos; Local type; if (args.size() == 2) { // IntPos CHECK_ARG_TYPE(args[1], ValueKind::kString); if (IsInstanceOf(args[0])) { // IntPos IntPos* posObj = IntPos::extractPos(args[0]); if (posObj->dim < 0) return Boolean::newBoolean(false); else { pos.x = posObj->x; pos.y = posObj->y; pos.z = posObj->z; pos.dim = posObj->dim; type = args[1]; } } else if (IsInstanceOf(args[0])) { // FloatPos FloatPos* posObj = FloatPos::extractPos(args[0]); if (posObj->dim < 0) return Boolean::newBoolean(false); else { pos = *posObj; type = args[1]; } } else { LOG_WRONG_ARG_TYPE(); return Local(); } } else if (args.size() == 5) { // Number Pos CHECK_ARG_TYPE(args[0], ValueKind::kNumber); CHECK_ARG_TYPE(args[1], ValueKind::kNumber); CHECK_ARG_TYPE(args[2], ValueKind::kNumber); CHECK_ARG_TYPE(args[3], ValueKind::kNumber); CHECK_ARG_TYPE(args[4], ValueKind::kString); pos = {args[0].asNumber().toFloat(), args[1].asNumber().toFloat(), args[2].asNumber().toFloat(), args[3].toInt()}; type = args[4]; } else { LOG_WRONG_ARGS_COUNT(); return Local(); } Global->spawnParticleEffect(type.toStr(), pos.getVec3(), Global->getDimension(pos.dim)); return Boolean::newBoolean(true); } CATCH("Fail in SpawnParticle!") }