├── .gitignore ├── .idea ├── .gitignore ├── MCBERedstoneSystem.iml ├── misc.xml ├── vcs.xml ├── modules.xml └── deployment.xml ├── src ├── component │ ├── CircuitComponentList.cpp │ ├── producer │ │ ├── capacitor │ │ │ ├── PulseCapacitor.cpp │ │ │ ├── RedstoneTorchCapacitor.cpp │ │ │ ├── PulseCapacitor.h │ │ │ ├── RedstoneTorchCapacitor.h │ │ │ ├── ComparatorCapacitor.cpp │ │ │ ├── ComparatorCapacitor.h │ │ │ ├── RepeaterCapacitor.h │ │ │ └── RepeaterCapacitor.cpp │ │ ├── ProducerComponent.cpp │ │ └── ProducerComponent.h │ ├── consumer │ │ ├── PistonConsumer.h │ │ ├── PistonConsumer.cpp │ │ ├── ConsumerComponent.h │ │ └── ConsumerComponent.cpp │ ├── CircuitTrackingInfo.cpp │ ├── transporter │ │ ├── TransporterComponent.h │ │ └── TransporterComponent.cpp │ ├── powered_block │ │ ├── PoweredBlockComponent.cpp │ │ └── PoweredBlockComponent.h │ ├── CircuitTrackingInfo.h │ ├── CircuitComponentList.h │ ├── bcc.txt │ ├── BaseCircuitComponent.h │ └── BaseCircuitComponent.cpp ├── mc │ ├── BlockSource.cpp │ ├── BlockSource.h │ ├── BlockPos.h │ └── BlockPos.cpp ├── CircuitSystem.h ├── CircuitSceneGraph.h ├── CircuitSystem.cpp └── CircuitSceneGraph.cpp ├── main.cpp ├── README.md ├── docs ├── producers.md ├── types.md └── consumers.md └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /cmake-build-debug/ -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/MCBERedstoneSystem.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/component/CircuitComponentList.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #include "CircuitComponentList.h" 6 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello, World!" << std::endl; 5 | return 0; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/PulseCapacitor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/4/4. 3 | // 4 | 5 | #include "PulseCapacitor.h" 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/RedstoneTorchCapacitor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/16. 3 | // 4 | 5 | #include "RedstoneTorchCapacitor.h" 6 | 7 | bool RedstoneTorchCapacitor::_canIncrementSelfPower() { 8 | return this->mCanReigniteFromBurnout ? false ? this->mSelfPowerCount <= 32; 9 | } 10 | -------------------------------------------------------------------------------- /src/mc/BlockSource.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/16. 3 | // 4 | 5 | #include "BlockSource.h" 6 | 7 | bool BlockSource::areChunksFullyLoaded(const BlockPos &pos, int radius) { 8 | //todo: 9 | return true; 10 | } 11 | 12 | bool BlockSource::hasChunksAt(BlockPos pos, int i) { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/PulseCapacitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/4/4. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_PULSECAPACITOR_H 6 | #define MCBEREDSTONESYSTEM_PULSECAPACITOR_H 7 | 8 | #include "../ProducerComponent.h" 9 | 10 | class PulseCapacitor : public CapacitorComponent { 11 | //todo 12 | }; 13 | 14 | 15 | #endif //MCBEREDSTONESYSTEM_PULSECAPACITOR_H 16 | -------------------------------------------------------------------------------- /src/mc/BlockSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/16. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_BLOCKSOURCE_H 6 | #define MCBEREDSTONESYSTEM_BLOCKSOURCE_H 7 | 8 | #include "BlockPos.h" 9 | class BlockSource { 10 | public: 11 | bool areChunksFullyLoaded(const BlockPos&pos,int radius); 12 | 13 | bool hasChunksAt(BlockPos pos, int i); 14 | }; 15 | 16 | 17 | #endif //MCBEREDSTONESYSTEM_BLOCKSOURCE_H 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCBE RedstoneSystem 2 | 3 | A try to implement Minecraft Bedrock Edition's Redstone System. 4 | It cannot be compiled, only be used for reading (based on Minecraft BE 1.14) 5 | More info: 6 | 7 | - [https://www.bilibili.com/read/cv6013612](https://www.bilibili.com/read/cv6013612) 8 | - [https://www.bilibili.com/read/cv7581645](https://www.bilibili.com/read/cv7581645) 9 | - [https://www.bilibili.com/read/cv7876046](https://www.bilibili.com/read/cv7876046) -------------------------------------------------------------------------------- /.idea/deployment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/producers.md: -------------------------------------------------------------------------------- 1 | | Block type | allowAttachments | 2 | | ---------------------- | ---------------- | 3 | | BarrelBlock | 1 | 4 | | ChestBlock | 1 | 5 | | DaylightDetectorBlock | 0 | 6 | | DetectorRailBlock | 1 | 7 | | JukeboxBlock | 1 | 8 | | LecternBlock | 1 | 9 | | LeverBlock | 1 | 10 | | RedstoneBlock | 0 | 11 | | TripWireHookBlock | 1 | 12 | | BasePressurePlateBlock | 1 | 13 | | ButtonBlock | 1 | 14 | 15 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/RedstoneTorchCapacitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/16. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_REDSTONETORCHCAPACITOR_H 6 | #define MCBEREDSTONESYSTEM_REDSTONETORCHCAPACITOR_H 7 | 8 | #include "component/producer/ProducerComponent.h" 9 | 10 | class RedstoneTorchCapacitor : public CapacitorComponent { 11 | 12 | //todo 13 | struct State { 14 | bool mOn; 15 | bool mHalfFrame; 16 | }; 17 | RedstoneTorchCapacitor *nextOrder{}; 18 | int mSelfPowerCount = 0; 19 | bool mCanReigniteFromBurnout = false; 20 | State mState[2]{}; 21 | public: 22 | bool _canIncrementSelfPower(); 23 | 24 | void addSource(); 25 | }; 26 | 27 | 28 | #endif //MCBEREDSTONESYSTEM_REDSTONETORCHCAPACITOR_H 29 | -------------------------------------------------------------------------------- /src/component/consumer/PistonConsumer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/27. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_PISTONCONSUMER_H 6 | #define MCBEREDSTONESYSTEM_PISTONCONSUMER_H 7 | 8 | #include "ConsumerComponent.h" 9 | 10 | class PistonConsumer : public ConsumerComponent { 11 | FACING mBlockedFace = FACING::NOT_DEFINED; 12 | 13 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) override; 14 | 15 | bool allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) override; 16 | 17 | ComponentTypeID getInstanceType() override { 18 | return MCPI; 19 | } 20 | 21 | void setBlockPowerFace(FACING facing); 22 | 23 | }; 24 | 25 | 26 | #endif //MCBEREDSTONESYSTEM_PISTONCONSUMER_H 27 | -------------------------------------------------------------------------------- /docs/types.md: -------------------------------------------------------------------------------- 1 | | component | BaseType | InstanceType | 2 | | ---------------------- | -------- | ------------ | 3 | | BaseCircuitComponent | CSSC | CSSC | 4 | | BaseRailTransporter | MCPR | MCPR | 5 | | ComparatorCapacitor | | MCCR | 6 | | ConsumerComponent | CSCC | CSCC | 7 | | PoweredBlockComponent | CSPB | CSPB | 8 | | ProducerComponent | CSPC | CSPC | 9 | | CapacitorComponent | CSCA | CSCA | 10 | | PistonConsumer | | MCPI | 11 | | PulseCapacitor | | MCPC | 12 | | RedstoneTorchCapacitor | | MCTC | 13 | | RepeaterCapacitor | | MCRR | 14 | | TransporterComponent | CSTR | CSTR | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/component/CircuitTrackingInfo.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #include "CircuitTrackingInfo.h" 6 | #include "BaseCircuitComponent.h" 7 | 8 | 9 | void initEntry(CircuitTrackingInfo::Entry &entry, BaseCircuitComponent *component, const BlockPos &pos) { 10 | entry.mComponent = component; 11 | entry.mDirection = component->getDirection(); 12 | entry.mPos = pos; 13 | entry.mTypeID = component->getBaseType(); 14 | } 15 | 16 | CircuitTrackingInfo::CircuitTrackingInfo(BaseCircuitComponent *component, const BlockPos &pos, int dampening) { 17 | 18 | initEntry(this->mCurrent, component, pos); 19 | initEntry(this->mPower, component, pos); 20 | initEntry(this->mNearest, component, pos); 21 | initEntry(this->m2ndNearest, component, pos); 22 | this->mDampening = dampening; 23 | this->mDirectlyPowered = true; 24 | this->mData = 0; 25 | } 26 | -------------------------------------------------------------------------------- /docs/consumers.md: -------------------------------------------------------------------------------- 1 | | Type name | mPropagatePower | mAcceptHalfPulse | 2 | | ----------------- | --------------- | ---------------- | 3 | | BaseRailBlock | 0 | 0 | 4 | | DoorBlock | 0 | 1 | 5 | | BellBlock | 1 | 0 | 6 | | CommandBlock | 1 | 0 | 7 | | DispenserBlock | 1 | 1 | 8 | | FenceGateBlock | 0 | 0 | 9 | | HopperBlock | 0 | 0 | 10 | | NoteBlock | 1 | 0 | 11 | | RedstoneLampBlock | 1 | 0 | 12 | | SkullBlock | 0 | 1 | 13 | | StructureBlock | 0 | 0 | 14 | | TntBlock | 0 | 0 | 15 | | TrapDoorBlock | 0 | 1 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/ComparatorCapacitor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/4/4. 3 | // 4 | 5 | #include "ComparatorCapacitor.h" 6 | 7 | bool 8 | ComparatorCapacitor::addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) { 9 | auto searchDir = info.mCurrent.mDirection; 10 | if (searchDir == FACING::NEG_Y || searchDir == FACING::POS_Y) return false; //不能从上面和下面搜索到 11 | if (searchDir == this->getDirection()) return false; //从比较器的输出端搜索,直接返回 12 | auto type = info.mNearest.mTypeID; 13 | if (searchDir == invFacing(this->getDirection())) { //如果是从比较器的侧面输入 14 | //不是红石 中继器 比较器就返回 (比较器侧面只允许这三种进行连接) 15 | if (type != CSTR && type != MCRR && type != MCCR)return false; 16 | } 17 | 18 | //同比较器[红石块][充能方块][比较器]无法激活 19 | if (type == CSPB && !info.mNearest.mComponent->hasDirectPower()) { 20 | return false; 21 | } 22 | return this->trackPowerSourceDuplicates(info, damping, directPowered); 23 | } 24 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | project(MCBERedstoneSystem) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | 7 | add_executable(MCBERedstoneSystem 8 | src/component/CircuitComponentList.cpp 9 | src/component/BaseCircuitComponent.cpp 10 | src/mc/BlockPos.cpp 11 | src/CircuitSystem.cpp 12 | src/component/CircuitTrackingInfo.cpp 13 | src/CircuitSceneGraph.cpp 14 | src/mc/BlockSource.cpp 15 | src/component/producer/ProducerComponent.cpp 16 | src/component/producer/capacitor/RedstoneTorchCapacitor.cpp 17 | src/component/producer/capacitor/PulseCapacitor.cpp 18 | src/component/producer/capacitor/RepeaterCapacitor.cpp 19 | src/component/producer/capacitor/ComparatorCapacitor.cpp 20 | src/component/transporter/TransporterComponent.cpp 21 | src/component/consumer/ConsumerComponent.cpp 22 | src/component/consumer/PistonConsumer.cpp 23 | src/component/powered_block/PoweredBlockComponent.cpp 24 | ) 25 | include_directories(MCBERedstoneSystem src) 26 | -------------------------------------------------------------------------------- /src/component/transporter/TransporterComponent.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/22. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_TRANSPORTERCOMPONENT_H 6 | #define MCBEREDSTONESYSTEM_TRANSPORTERCOMPONENT_H 7 | 8 | #include "component/BaseCircuitComponent.h" 9 | 10 | 11 | /* 12 | * 这里是红石粉的逻辑实现 13 | */ 14 | class TransporterComponent : public BaseCircuitComponent { 15 | private: 16 | int mNextStrength = 0; 17 | public: 18 | //todo 19 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) override; 20 | 21 | //todo 22 | bool allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) override; 23 | 24 | void cacheValues(CircuitSystem &, const BlockPos &pos) override; 25 | 26 | bool canConsumerPower() override { return true; } 27 | 28 | bool evaluate(CircuitSystem &, const BlockPos &) override; 29 | 30 | ComponentTypeID getBaseType() override { return CSTR; } 31 | 32 | ComponentTypeID getInstanceType() override { return CSTR; } 33 | 34 | 35 | }; 36 | 37 | 38 | #endif //MCBEREDSTONESYSTEM_TRANSPORTERCOMPONENT_H 39 | -------------------------------------------------------------------------------- /src/component/powered_block/PoweredBlockComponent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/31. 3 | // 4 | 5 | #include "PoweredBlockComponent.h" 6 | 7 | bool PoweredBlockComponent::addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, 8 | bool &directPowered) { 9 | //todo 10 | 11 | return false; 12 | } 13 | 14 | bool PoweredBlockComponent::allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) { 15 | auto typeID = info.mCurrent.mTypeID; 16 | if (typeID == CSTR) { 17 | return this->mPromotedToProducer; 18 | } else { 19 | return typeID != CSPB; 20 | } 21 | } 22 | 23 | //充能方块的红石信号是获取的时候实时计算的,没有缓存 24 | int PoweredBlockComponent::getStrength() const { 25 | int newStrength = 0; 26 | for (auto &source: this->mSources.mComponents) { 27 | auto currentStrength = source.mComponent->getStrength() - source.mDampening; 28 | if (currentStrength < 0)currentStrength = 0; 29 | if (newStrength < currentStrength) 30 | newStrength = currentStrength; 31 | } 32 | return newStrength; 33 | } 34 | -------------------------------------------------------------------------------- /src/component/producer/ProducerComponent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/16. 3 | // 4 | 5 | #include "ProducerComponent.h" 6 | 7 | void ProducerComponent::allowAttachments(bool attached) { 8 | this->mAttachedAllowed = attached; 9 | } 10 | 11 | bool 12 | ProducerComponent::allowConnection(CircuitSceneGraph &graph, const CircuitTrackingInfo &info, bool bDirectlyPowered) { 13 | if (this->mAttachedAllowed) return true; 14 | return this->getBaseType() != CSPB; 15 | } 16 | 17 | 18 | ComponentTypeID ProducerComponent::getBaseType() { 19 | return CSPC; 20 | } 21 | 22 | ComponentTypeID ProducerComponent::getInstanceType() { 23 | return CSPC; 24 | } 25 | 26 | 27 | void ProducerComponent::setStrength(int strength) { 28 | this->mNextStrength = strength; 29 | if (this->mIsFirstTime) 30 | this->mStrength = mNextStrength; 31 | } 32 | 33 | 34 | bool ProducerComponent::evaluate(CircuitSystem &, const BlockPos &) { 35 | this->mStrength = this->mNextStrength; 36 | return false; 37 | } 38 | 39 | ComponentTypeID CapacitorComponent::getBaseType() { 40 | return CSCA; 41 | } 42 | 43 | ComponentTypeID CapacitorComponent::getInstanceType() { 44 | return CSCA; 45 | } 46 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/ComparatorCapacitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/4/4. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_COMPARATORCAPACITOR_H 6 | #define MCBEREDSTONESYSTEM_COMPARATORCAPACITOR_H 7 | 8 | #include "../ProducerComponent.h" 9 | 10 | class ComparatorCapacitor : public CapacitorComponent { 11 | //todo 12 | int mRearAnalogStrength = -1; 13 | int mSideAnalogStrengthRight = -1; 14 | int mSideAnalogStrengthLeft = -1; 15 | int mOldStrength = 0; 16 | int mMode = 0; 17 | int mRearStrength = 0; 18 | int mSideStrengths = 0; 19 | int mHasAnalogBeenSet = 0; 20 | CircuitComponentList mSideComponents; 21 | 22 | FACING getPoweroutDirection() { 23 | return this->getDirection(); 24 | } 25 | 26 | inline int getOldStrength() const { 27 | return this->mOldStrength; 28 | } 29 | 30 | bool allowConnection(CircuitSceneGraph *graph, const CircuitTrackingInfo *info, bool *bDirectlyPowered) { 31 | return info->mCurrent.mDirection == this->getPoweroutDirection(); 32 | } 33 | 34 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) override; 35 | 36 | }; 37 | 38 | 39 | #endif //MCBEREDSTONESYSTEM_COMPARATORCAPACITOR_H 40 | -------------------------------------------------------------------------------- /src/component/CircuitTrackingInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_CIRCUITTRACKINGINFO_H 6 | #define MCBEREDSTONESYSTEM_CIRCUITTRACKINGINFO_H 7 | 8 | #include "mc/BlockPos.h" 9 | 10 | class BaseCircuitComponent; 11 | 12 | enum ComponentTypeID : uint64_t { 13 | CSSC = 1129534275, 14 | CSPB = 1129533506, //充能方块 15 | CSPC, //生产者 16 | CSCA, //电容器 17 | CSTR, //传输者 18 | CSCC, 19 | MCPI, //活塞 20 | MCPR, //铁轨 21 | MCRR, 22 | MCCR 23 | }; 24 | 25 | 26 | class CircuitTrackingInfo { 27 | public: 28 | struct Entry { 29 | BaseCircuitComponent *mComponent = nullptr; 30 | BlockPos mPos; 31 | FACING mDirection = NEG_Y; 32 | ComponentTypeID mTypeID = CSSC; 33 | }; 34 | Entry mCurrent; 35 | Entry mPower; 36 | Entry mNearest; 37 | Entry m2ndNearest; 38 | bool mDirectlyPowered = true; 39 | int mData = 0; 40 | int mDampening; 41 | 42 | 43 | CircuitTrackingInfo(BaseCircuitComponent *component, const BlockPos &pos, int dampening); 44 | 45 | }; 46 | 47 | void 48 | initEntry(CircuitTrackingInfo::Entry &entry, BaseCircuitComponent *component, 49 | const BlockPos &pos); 50 | 51 | #endif //MCBEREDSTONESYSTEM_CIRCUITTRACKINGINFO_H 52 | -------------------------------------------------------------------------------- /src/component/powered_block/PoweredBlockComponent.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/31. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_POWEREDBLOCKCOMPONENT_H 6 | #define MCBEREDSTONESYSTEM_POWEREDBLOCKCOMPONENT_H 7 | 8 | #include "component/BaseCircuitComponent.h" 9 | 10 | class PoweredBlockComponent : public BaseCircuitComponent { 11 | bool mPromotedToProducer = false; 12 | bool mAllowAsPowerSource = true; 13 | bool mIsFirstTime = false; 14 | public: 15 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) override; 16 | 17 | bool allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) override; 18 | 19 | 20 | bool canConsumerPower() override { return true; } 21 | 22 | bool evaluate(CircuitSystem &, const BlockPos &) override { 23 | return false; 24 | } 25 | 26 | ComponentTypeID getBaseType() override { return CSPB; } 27 | 28 | ComponentTypeID getInstanceType() override { return CSPB; } 29 | 30 | int getStrength() const override; 31 | 32 | bool hasChildrenSource() override { return true; } 33 | 34 | bool isAllowAsPowerSource() const { 35 | return this->mAllowAsPowerSource; 36 | }; 37 | 38 | bool isPromotedToProducer() const { return this->mPromotedToProducer; } 39 | }; 40 | 41 | 42 | #endif //MCBEREDSTONESYSTEM_POWEREDBLOCKCOMPONENT_H 43 | -------------------------------------------------------------------------------- /src/component/consumer/PistonConsumer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/27. 3 | // 4 | 5 | #include "PistonConsumer.h" 6 | 7 | //在y轴方向上活塞方块的特殊值和激活方向相反 8 | //因此才来这么一个函数 9 | void PistonConsumer::setBlockPowerFace(FACING facing) { 10 | if (facing == NEG_Y) { 11 | this->mBlockedFace = POS_Y; 12 | } else { 13 | if (facing == POS_Y) { 14 | this->mBlockedFace = NEG_Y; 15 | } else { 16 | this->mBlockedFace = facing; 17 | } 18 | } 19 | } 20 | 21 | bool PistonConsumer::addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) { 22 | if (this->mBlockedFace == info.mCurrent.mDirection)return false; //从活塞推出面搜索到信号源,直接返回false 23 | auto mTypeId = info.mNearest.mTypeID; 24 | //这里应该是电容器的背面无法激活活塞 25 | //比如中继器的背面对着活塞 26 | if (mTypeId == CSCA && info.mCurrent.mDirection == info.mNearest.mComponent->getDirection()) { 27 | return false; 28 | } 29 | 30 | //这边是充能方块无法[非直接]激活活塞,实测所有的激活方法针对活塞都是直接激活,没有非直接的情况 31 | if (mTypeId == CSPB && !directPowered) { 32 | return false; 33 | } 34 | 35 | this->trackPowerSource(info, damping, directPowered, info.mCurrent.mDirection == invFacing(this->getDirection())); 36 | return false; 37 | } 38 | 39 | bool PistonConsumer::allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) { 40 | return true; 41 | } 42 | -------------------------------------------------------------------------------- /src/component/consumer/ConsumerComponent.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/22. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_CONSUMERCOMPONENT_H 6 | #define MCBEREDSTONESYSTEM_CONSUMERCOMPONENT_H 7 | 8 | #include "component/BaseCircuitComponent.h" 9 | 10 | class ConsumerComponent : public BaseCircuitComponent { 11 | 12 | bool mSecondaryPowered = false; 13 | bool mPropagatePower = false; //是否能强充能后面的方块 14 | bool mPromotedToProducer = false; 15 | bool mAcceptHalfPulse = false; //是否接受半脉冲 16 | public: 17 | 18 | 19 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) override; 20 | 21 | /* 22 | * 是否运行当前原件和info中的mCurrent中的原件相连接 23 | */ 24 | bool allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) override; 25 | 26 | bool canConsumerPower() override { return true; } 27 | 28 | bool evaluate(CircuitSystem &, const BlockPos &) override; 29 | 30 | ComponentTypeID getBaseType() override { return CSCC; } 31 | 32 | ComponentTypeID getInstanceType() override { return CSCC; } 33 | 34 | bool isPromotedToProducer() const { return this->mPromotedToProducer; } 35 | 36 | bool isSecondaryPowered() override { return this->mSecondaryPowered; } 37 | 38 | void setAcceptHalfPulse(bool accept) { this->mAcceptHalfPulse = accept; } 39 | 40 | void setPropagatePower(bool propagatePower) { this->mPropagatePower = propagatePower; } 41 | 42 | }; 43 | 44 | 45 | #endif //MCBEREDSTONESYSTEM_CONSUMERCOMPONENT_H 46 | -------------------------------------------------------------------------------- /src/component/producer/ProducerComponent.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/16. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_PRODUCERCOMPONENT_H 6 | #define MCBEREDSTONESYSTEM_PRODUCERCOMPONENT_H 7 | 8 | #include "component/BaseCircuitComponent.h" 9 | 10 | class CircuitSceneGraph; 11 | 12 | class ProducerComponent : public BaseCircuitComponent { 13 | int mNextStrength = 0; 14 | bool mStopPower = false; 15 | bool mAttachedAllowed = false; //是否允许附着在充能方块上给充能方块强充能 仅有红石块和阳光侦测器不能 16 | 17 | public: 18 | void allowAttachments(bool attached); 19 | 20 | bool allowConnection(CircuitSceneGraph &graph, const CircuitTrackingInfo &info, bool bDirectlyPowered); 21 | 22 | bool canStopPower() const { 23 | return this->mStopPower; 24 | } 25 | 26 | bool doesAllowAttachments() const { 27 | return this->mAttachedAllowed; 28 | } 29 | 30 | bool evaluate(CircuitSystem &, const BlockPos &) override; 31 | 32 | ComponentTypeID getBaseType() override; 33 | 34 | ComponentTypeID getInstanceType() override; 35 | 36 | void setStrength(int strength) override; 37 | 38 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, 39 | bool &directPowered) override { return true; } 40 | }; 41 | 42 | class CapacitorComponent : public ProducerComponent { 43 | ComponentTypeID getBaseType() override; 44 | 45 | ComponentTypeID getInstanceType() override; 46 | 47 | FACING getPowerOutDirection() const { return FACING::NOT_DEFINED; } 48 | 49 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, 50 | bool &directPowered) override { return true; } 51 | 52 | }; 53 | 54 | #endif //MCBEREDSTONESYSTEM_PRODUCERCOMPONENT_H 55 | -------------------------------------------------------------------------------- /src/CircuitSystem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_CIRCUITSYSTEM_H 6 | #define MCBEREDSTONESYSTEM_CIRCUITSYSTEM_H 7 | 8 | #include "CircuitSceneGraph.h" 9 | #include 10 | #include "mc/BlockSource.h" 11 | 12 | /* 13 | * 大体上就是CircuitSceneGraph的一个封装 14 | */ 15 | class CircuitSystem { 16 | struct LevelChunkTracking { 17 | 18 | }; 19 | bool mLockGraph = true; 20 | CircuitSceneGraph mSceneGraph; 21 | std::vector mAddedLevelChunk; 22 | bool mHasBeenEvaluated = true; 23 | 24 | void _shouldEvaluate(BlockSource *source); 25 | 26 | public: 27 | void update(BlockSource *region); 28 | 29 | void evaluate(BlockSource *region); 30 | 31 | 32 | void cacheValues(); 33 | 34 | void evaluateComponents(bool bOnlyProducers); 35 | 36 | void checkLocks(); 37 | 38 | 39 | BaseCircuitComponent * 40 | createComponent(const BlockPos &pos, FACING direction, std::unique_ptr newComponent); 41 | 42 | FACING getDirection(const BlockPos &pos); 43 | 44 | int getStrength(const BlockPos &pos); 45 | 46 | bool hasDirectPower(const BlockPos &pos); 47 | 48 | bool invalidatePos(const BlockPos &pos); 49 | 50 | bool isAvailableAt(const BlockPos &pos); 51 | 52 | inline bool lockGraph(bool bLock) { this->mLockGraph = bLock; } 53 | 54 | void preSetupPoweredBlocks(const ChunkPos &pos); 55 | 56 | 57 | /* 58 | * 部分方块被移除的回调函数里面会调用这个函数用于移除红石系统中的红石组件 59 | */ 60 | void removeComponents(const BlockPos &pos); 61 | 62 | void setStrength(const BlockPos &pos, int strength); 63 | 64 | void updateDependencies(BlockSource *blockSource); 65 | }; 66 | 67 | 68 | #endif //MCBEREDSTONESYSTEM_CIRCUITSYSTEM_H 69 | -------------------------------------------------------------------------------- /src/component/CircuitComponentList.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_CIRCUITCOMPONENTLIST_H 6 | #define MCBEREDSTONESYSTEM_CIRCUITCOMPONENTLIST_H 7 | 8 | #include "mc/BlockPos.h" 9 | 10 | class BaseCircuitComponent; 11 | 12 | 13 | /** 14 | * 信号源表,其实就是对std::vector的一个简单封装 15 | */ 16 | class CircuitComponentList { 17 | public: 18 | /* 19 | * 信号源表内的一个表项 20 | */ 21 | struct Item { 22 | BaseCircuitComponent *mComponent = nullptr; //指向信号源的指针 23 | int mDampening = 0; //和信号源的距离 24 | BlockPos mPos{}; //信号源的位置 25 | FACING mDirection = FACING::NOT_DEFINED; //信号源的方向 26 | bool mDirectlyPowered = false; //是否被信号源直接激活 27 | int mData = 0; //额外数据值,用途未知 28 | 29 | Item() = default; 30 | 31 | Item(BaseCircuitComponent *component, int dampening, const BlockPos &pos) : mComponent(component), 32 | mDampening(dampening), mPos(pos) {} 33 | }; 34 | 35 | std::vector mComponents; 36 | 37 | auto end() { 38 | return mComponents.end(); 39 | } 40 | 41 | auto begin() { 42 | return mComponents.begin(); 43 | } 44 | 45 | void push_back(Item &item) { 46 | this->mComponents.push_back(item); 47 | } 48 | 49 | auto size() const { 50 | return this->mComponents.size(); 51 | } 52 | 53 | /** 54 | * 从信号源表中移除特定位置的信号源,O(n) 55 | * @param posSource 位置 56 | * @param component 无效参数 57 | * @return 是否成功移除 58 | */ 59 | bool removeSource(const BlockPos &posSource, const BaseCircuitComponent *component) { 60 | bool found = false; 61 | auto it = this->mComponents.begin(); 62 | for (; it != this->mComponents.end();) { 63 | if (it->mPos == posSource) { 64 | it = this->mComponents.erase(it); 65 | found = true; 66 | } else { 67 | ++it; 68 | } 69 | } 70 | 71 | return found; 72 | } 73 | 74 | 75 | //往信号源表尾部添加一个新的信号源 76 | void add(BaseCircuitComponent *component, int damping, const BlockPos &pos) { 77 | Item item(component, damping, pos); 78 | this->mComponents.push_back(item); 79 | } 80 | }; 81 | 82 | 83 | #endif //MCBEREDSTONESYSTEM_CIRCUITCOMPONENTLIST_H 84 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/RepeaterCapacitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/4/4. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_REPEATERCAPACITOR_H 6 | #define MCBEREDSTONESYSTEM_REPEATERCAPACITOR_H 7 | 8 | #include "../ProducerComponent.h" 9 | 10 | 11 | int clamp(int x, int min, int max) { 12 | if (x < min)return min; 13 | if (x > max)return max; 14 | return x; 15 | } 16 | 17 | //中继器 18 | //看不懂,比我想的要复杂一些,不知道写的啥玩意 19 | 20 | class RepeaterCapacitor : public CapacitorComponent { 21 | 22 | enum Status { 23 | OFF = 0, 24 | ON = 1, 25 | OFF_LOCKED = 2, 26 | ON_LOCKED = 3 27 | }; 28 | 29 | //todo 30 | int mInsertAt = 0; //挡位(0,1,2,3) 31 | bool mPowered = false; //有无信号 32 | Status mNextPower = OFF; 33 | bool mLocked = true; 34 | int mPulseCount = 0; 35 | int mPulse = 0; 36 | int mNextPulse = 0; 37 | Status mOnStates[5]{}; 38 | CircuitComponentList mSideComponents; 39 | 40 | RepeaterCapacitor() { 41 | for (int i = 0; i < 4; ++i) 42 | mOnStates[i] = OFF_LOCKED; 43 | } 44 | 45 | inline FACING getPoweroutDirection() { 46 | return this->getDirection(); 47 | } 48 | 49 | bool allowConnection(CircuitSceneGraph *graph, const CircuitTrackingInfo *info, bool *bDirectlyPowered) { 50 | return info->mCurrent.mDirection == this->getPoweroutDirection(); 51 | } 52 | 53 | 54 | bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) override; 55 | 56 | void setStrength(int strength) override { 57 | this->mPowered = strength != 0; 58 | for (int i = 0; i < this->mInsertAt + 1; ++i) { 59 | this->mOnStates[i] = this->mPowered ? ON_LOCKED : OFF_LOCKED; 60 | } 61 | for (int i = this->mInsertAt + 1; i <= 4; ++i) { 62 | this->mOnStates[i] = OFF; 63 | } 64 | } 65 | 66 | 67 | int getStrength() const override { 68 | return this->mPowered ? 15 : 0; 69 | } 70 | 71 | void setDelay(int delay) { 72 | this->mInsertAt = clamp(delay, 0, 3); 73 | } 74 | 75 | //addSource和AllowConnection不写了 76 | bool evaluate(CircuitSystem &system, const BlockPos &pos) override; 77 | 78 | 79 | void delayPulse(Status status); 80 | 81 | void alternatePulse(); 82 | 83 | void extendPulse(); 84 | }; 85 | 86 | 87 | #endif //MCBEREDSTONESYSTEM_REPEATERCAPACITOR_H 88 | -------------------------------------------------------------------------------- /src/component/producer/capacitor/RepeaterCapacitor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/4/4. 3 | // 4 | 5 | #include "RepeaterCapacitor.h" 6 | 7 | void RepeaterCapacitor::delayPulse(RepeaterCapacitor::Status status) { 8 | //todo 9 | } 10 | 11 | bool RepeaterCapacitor::evaluate(CircuitSystem &system, const BlockPos &pos) { 12 | auto oldPowered = this->mPowered; 13 | if (this->mLocked) { //NOLINT 14 | return false; 15 | } 16 | this->delayPulse(this->mNextPower); 17 | if (this->mInsertAt > 0) { 18 | auto v5 = this->mPulse ? this->mPulseCount == 2 : false; 19 | if (this->mPulseCount > this->mInsertAt && !v5) { 20 | this->alternatePulse(); 21 | } else { 22 | this->extendPulse(); 23 | } 24 | } 25 | 26 | auto powered = true; 27 | 28 | this->mPowered = this->mOnStates[0] != ON ? ON_LOCKED : ON; 29 | return oldPowered != this->mPowered; 30 | 31 | } 32 | 33 | void RepeaterCapacitor::alternatePulse() { 34 | auto currentStatus = OFF; 35 | if (this->mInsertAt > 0) { 36 | currentStatus = this->mOnStates[0]; 37 | if (currentStatus == OFF || currentStatus == ON) { 38 | auto newStatus = this->mNextPulse ? ON_LOCKED : OFF_LOCKED; 39 | this->mNextPulse = ~this->mNextPulse; 40 | for (int i = 0; i < this->mInsertAt + 1; ++i) { 41 | this->mOnStates[i] = newStatus; 42 | } 43 | } 44 | } 45 | } 46 | 47 | void RepeaterCapacitor::extendPulse() { 48 | 49 | } 50 | 51 | bool 52 | RepeaterCapacitor::addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) { 53 | 54 | //这两个参数不知道写反了没,因为不清楚中继器的默认方向是咋样的 55 | auto forward = this->getDirection() == info->mCurrent.mDirection; //信号到来的方向和中继器方向是否相反 56 | auto backward = invFacing(this->getDirection()) == info->mCurrent.mDirection; //信号是不是从输入端来的 57 | if (forward)return false; //从反方向来的直接返回false 58 | 59 | //如果是充能方块且(充能方块没有信号源 or 充能方块是非直接激活)直接返回 60 | //类似这种电路 [红石][铁块][中继器]三个连一起,红石没法搜索到中继器 61 | if (info->mNearest.mTypeID == CSPB && (!info->mNearest.mComponent->hasDirectPower() || !bDirectlyPowered)) 62 | return false; 63 | auto type = info->mNearest.mComponent->getInstanceType(); 64 | if (backward || type == MCRR || type == MCCR) { 65 | //如果上一个原件是比较器或者中继器就两边也能输入(只有中继器和比较器能锁存中继器) 66 | //如果不是,只能从输入端输入 67 | this->trackPowerSource(info, dampening, bDirectlyPowered, backward); 68 | } 69 | 70 | return true; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/mc/BlockPos.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2020/10/22. 3 | // 4 | 5 | #ifndef LIBMCBEMOD_BLOCKPOS_H 6 | #define LIBMCBEMOD_BLOCKPOS_H 7 | 8 | #include 9 | #include 10 | 11 | class BlockPos; 12 | 13 | 14 | enum FACING { 15 | NEG_Y = 0, 16 | POS_Y = 1, 17 | NEG_Z = 2, 18 | POS_Z = 3, 19 | NEG_X = 4, 20 | POS_X = 5, 21 | NOT_DEFINED = 6 22 | }; 23 | 24 | bool facingIsPos(FACING facing); 25 | 26 | bool facingIsNeg(FACING facing); 27 | 28 | bool facingIsX(FACING facing); 29 | 30 | bool facingIsY(FACING facing); 31 | 32 | bool facingIsZ(FACING facing); 33 | 34 | FACING invFacing(FACING facing); 35 | 36 | std::string facingToString(FACING facing); 37 | 38 | std::string facingToDirString(FACING facing); 39 | 40 | BlockPos facingToBlockPos(FACING facing); 41 | 42 | struct BlockPos2 { 43 | int x = 0; 44 | int z = 0; 45 | 46 | BlockPos2(int _x, int _z) : x(_x), z(_z) {} 47 | 48 | std::string toString() const; 49 | 50 | bool isSlimeChunk() const; 51 | 52 | bool operator<(const BlockPos2 &rhs) const; 53 | }; 54 | 55 | typedef BlockPos2 ChunkPos; 56 | 57 | 58 | class BlockPos { 59 | public: 60 | int x = 0; 61 | int y = 0; 62 | int z = 0; 63 | 64 | BlockPos() = default; 65 | 66 | BlockPos(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {} 67 | 68 | explicit BlockPos(int x) : BlockPos(x, x, x) {} 69 | 70 | explicit BlockPos(float x) : BlockPos(x, x, x) {} 71 | 72 | BlockPos(float _x, float _y, float _z) : x((int) _x), y((int) _y), z((int) _z) {} 73 | 74 | bool operator==(const BlockPos &v) const; 75 | 76 | bool operator!=(const BlockPos &v) const; 77 | 78 | float distanceTo(const BlockPos &blockPos) const; 79 | 80 | friend std::ostream &operator<<(std::ostream &os, const BlockPos &vec3); 81 | 82 | std::string toString() const; 83 | 84 | std::vector getNeighbourPos(); 85 | 86 | std::vector getPlainNeighbourPos(); 87 | 88 | BlockPos2 toChunkPos() const; 89 | 90 | BlockPos2 InChunkOffset() const; 91 | 92 | 93 | int operator*(const BlockPos &pos) const; 94 | 95 | BlockPos operator+(const BlockPos &pos) const; 96 | 97 | bool operator<(const BlockPos &rhs) const; 98 | 99 | }; 100 | namespace std { 101 | template<> //function-template-specialization 102 | class hash { 103 | public : 104 | size_t operator()(const BlockPos &name) const { 105 | //todo write hash function 106 | return 0; 107 | } 108 | }; 109 | }; 110 | #endif //LIBMCBEMOD_BLOCKPOS_H 111 | -------------------------------------------------------------------------------- /src/component/transporter/TransporterComponent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/22. 3 | // 4 | 5 | #include "TransporterComponent.h" 6 | #include "component/powered_block/PoweredBlockComponent.h" 7 | #include "component/consumer/ConsumerComponent.h" 8 | 9 | bool 10 | TransporterComponent::addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) { 11 | auto type = info.mNearest.mTypeID; 12 | if (type == CSPB && !directPowered)return false; //弱充能检查 13 | 14 | if (type == CSPC || type == CSTR || type == CSCA) { 15 | directPowered = true; //生产者 红石线 能量源 16 | } else if (type == CSPB && 17 | dynamic_cast(info.mNearest.mComponent)->isPromotedToProducer()) { 18 | directPowered = true; 19 | } else if (type && dynamic_cast(info.mNearest.mComponent)->isPromotedToProducer()) { 20 | directPowered = true; 21 | } else { 22 | auto dir = info.mCurrent.mDirection; 23 | if (dir != NEG_Y && dir != invFacing(info.mNearest.mDirection)) { 24 | //只有这一种情况是非直接激活 25 | //连接没有被提升为生产者的充能方块or消费者,且两次输入的方向不同,这里还没找到情况,因此暂时不知道 26 | directPowered = info.mCurrent.mDirection == info.mNearest.mDirection; 27 | } 28 | } 29 | 30 | return this->trackPowerSource(info, ++damping, directPowered, 0); 31 | } 32 | 33 | bool TransporterComponent::allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) { 34 | if (info.mCurrent.mDirection == FACING::POS_Y) { return false; }//从正上方来的原件绝对禁止连接 35 | 36 | if (info.mCurrent.mDirection == FACING::NEG_Y || 37 | info.mCurrent.mComponent->consumePowerAnyDirection()) { return true; } //如果六个方向都接受连接,直接返回true 38 | 39 | auto type = info.mCurrent.mTypeID; 40 | if (type == CSTR) { 41 | auto dy = info.mCurrent.mPos.y - info.mNearest.mPos.y; 42 | /* 43 | * [current] 44 | * [ nearest] 45 | */ 46 | if (dy >= 0) { 47 | //从下往下传输上方的方块组织信号传输 48 | if (dy > 0 /**/) { 49 | return false; 50 | } else { 51 | 52 | 53 | } 54 | 55 | } 56 | 57 | 58 | } 59 | 60 | 61 | return false; 62 | } 63 | 64 | 65 | //找能提供最大能量的信号源 66 | void TransporterComponent::cacheValues(CircuitSystem &, const BlockPos &pos) { 67 | int currentStrength = 0, newStrength = 0; 68 | for (auto &item: this->mSources.mComponents) { 69 | currentStrength = item.mComponent->getStrength() - item.mDampening; 70 | if (currentStrength < 0) { 71 | currentStrength = 0; 72 | } 73 | if (newStrength < currentStrength) { 74 | newStrength = currentStrength; 75 | } 76 | } 77 | this->mNextStrength = newStrength; 78 | } 79 | 80 | //更新信号 81 | bool TransporterComponent::evaluate(CircuitSystem &, const BlockPos &) { 82 | bool changed = this->mStrength != this->mNextStrength; 83 | this->mStrength = this->mNextStrength; 84 | return changed; 85 | } 86 | -------------------------------------------------------------------------------- /src/component/consumer/ConsumerComponent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/22. 3 | // 4 | 5 | #include "ConsumerComponent.h" 6 | #include "component/producer/ProducerComponent.h" 7 | 8 | bool 9 | ConsumerComponent::addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) { 10 | 11 | auto id = info.mNearest.mTypeID; 12 | auto prevDp = directPowered; 13 | directPowered = false; //先把dp强制设成false 14 | this->mPromotedToProducer = false;//重置强充能状态 15 | if (this->mPropagatePower) { 16 | //当前原件能强充能 17 | if (id == CSPC) { 18 | //直连生产者 19 | auto *producer = dynamic_cast(info.mNearest.mComponent); 20 | //该信号源要能强充能充能方块or消费者且连接方向没问题 21 | //第一个条件红石块和阳光传感器不满足 22 | //第二个条件拉杆的附着方向不对也不满足 23 | directPowered = producer->doesAllowAttachments() && info.mCurrent.mDirection == producer->getDirection(); 24 | //直接激活就是被强充能了 25 | this->mPromotedToProducer = directPowered; 26 | } else if (id == CSCA) { 27 | directPowered = info.mCurrent.mDirection == FACING::POS_Y; 28 | //TODO 电容器 29 | auto dirPower = info.mNearest.mComponent->getDirection(); 30 | // if (dirPower != FACING::NOT_DEFINED) { 31 | // auto capacitor = dynamic_cast(info.mNearest.mComponent); 32 | // 33 | // } 34 | } else if (id == CSTR) { 35 | directPowered = true; 36 | } else { 37 | if (id == CSPB && !prevDp) { 38 | return false; 39 | } 40 | } 41 | } else if (id == CSPB && !prevDp) { 42 | //不能强充能 43 | return false; 44 | } 45 | return this->trackPowerSource(info, damping, directPowered, id == CSSC); 46 | } 47 | 48 | bool ConsumerComponent::allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered) { 49 | //todo 50 | auto id = info.mCurrent.mTypeID; 51 | 52 | if (id != CSCA) { //不是电容器 53 | if (id == CSTR && this->mPropagatePower) { //是红石线且能被强充能 54 | return this->mPromotedToProducer; //还要看是否被强充能了 55 | } 56 | return info.mDirectlyPowered; //没懂 57 | } 58 | //是电容器的情况 59 | //TODO: 没看懂 60 | return false; 61 | } 62 | 63 | 64 | bool ConsumerComponent::evaluate(CircuitSystem &, const BlockPos &) { 65 | int newStrength = 0; 66 | for (auto &source: this->mSources.mComponents) { 67 | int currentStrength = source.mComponent->getStrength() - source.mDampening; 68 | if (source.mComponent->isHalfPulse() && !this->mAcceptHalfPulse) { 69 | currentStrength = 15 - source.mDampening; 70 | } 71 | //半脉冲特判定 72 | if (currentStrength < 0)currentStrength = 0; 73 | if (newStrength < currentStrength) { 74 | this->mSecondaryPowered = source.mData == 1; 75 | newStrength = currentStrength; 76 | } 77 | } 78 | auto hasChanged = this->mStrength != newStrength; 79 | this->mStrength = newStrength; 80 | return hasChanged; 81 | } 82 | -------------------------------------------------------------------------------- /src/component/bcc.txt: -------------------------------------------------------------------------------- 1 | .data.rel.ro:000000000AF08818 dq offset _ZN20BaseCircuitComponentD0Ev ; BaseCircuitComponent::~BaseCircuitComponent() 2 | .data.rel.ro:000000000AF08820 dq offset _ZNK20BaseCircuitComponent11getStrengthEv ; BaseCircuitComponent::getStrength(void) 3 | .data.rel.ro:000000000AF08828 dq offset _ZNK20BaseCircuitComponent12getDirectionEv ; BaseCircuitComponent::getDirection(void) 4 | .data.rel.ro:000000000AF08830 dq offset _ZN20BaseCircuitComponent11setStrengthEi ; BaseCircuitComponent::setStrength(int) 5 | 5 .data.rel.ro:000000000AF08838 dq offset _ZN20BaseCircuitComponent12setDirectionEh ; BaseCircuitComponent::setDirection(uchar) 6 | .data.rel.ro:000000000AF08840 dq offset _ZN20BaseCircuitComponent24consumePowerAnyDirectionEv ; BaseCircuitComponent::consumePowerAnyDirection(void) 7 | .data.rel.ro:000000000AF08848 dq offset _ZN20BaseCircuitComponent16canConsumerPowerEv ; BaseCircuitComponent::canConsumerPower(void) 8 | .data.rel.ro:000000000AF08850 dq offset _ZN20BaseCircuitComponent12canStopPowerEv ; BaseCircuitComponent::canStopPower(void) 9 | .data.rel.ro:000000000AF08858 dq offset _ZN20BaseCircuitComponent12setStopPowerEb ; BaseCircuitComponent::setStopPower(bool) 10 | 10 .data.rel.ro:000000000AF08860 dq offset _ZNK20BaseCircuitComponent11getBaseTypeEv ; BaseCircuitComponent::getBaseType(void) 11 | .data.rel.ro:000000000AF08868 dq offset _ZNK20BaseCircuitComponent15getInstanceTypeEv ; BaseCircuitComponent::getInstanceType(void) 12 | .data.rel.ro:000000000AF08870 dq offset _ZN20BaseCircuitComponent12removeSourceERK8BlockPosPKS_ ; BaseCircuitComponent::removeSource(BlockPos const&,BaseCircuitComponent const*) 13 | .data.rel.ro:000000000AF08878 dq offset _ZN20BaseCircuitComponent9addSourceER17CircuitSceneGraphRK19CircuitTrackingInfoRiRb ; BaseCircuitComponent::addSource(CircuitSceneGraph &,CircuitTrackingInfo const&,int &,bool &) 14 | .data.rel.ro:000000000AF08880 dq offset _ZN20BaseCircuitComponent15allowConnectionER17CircuitSceneGraphRK19CircuitTrackingInfoRb ; BaseCircuitComponent::allowConnection(CircuitSceneGraph &,CircuitTrackingInfo const&,bool &) 15 | 15.data.rel.ro:000000000AF08888 dq offset _ZN20BaseCircuitComponent9checkLockER13CircuitSystemRK8BlockPos ; BaseCircuitComponent::checkLock(CircuitSystem &,BlockPos const&) 16 | .data.rel.ro:000000000AF08890 dq offset _ZN20BaseCircuitComponent8evaluateER13CircuitSystemRK8BlockPos ; BaseCircuitComponent::evaluate(CircuitSystem &,BlockPos const&) 17 | .data.rel.ro:000000000AF08898 dq offset _ZN20BaseCircuitComponent11cacheValuesER13CircuitSystemRK8BlockPos ; BaseCircuitComponent::cacheValues(CircuitSystem &,BlockPos const&) 18 | .data.rel.ro:000000000AF088A0 dq offset _ZN20BaseCircuitComponent18updateDependenciesER17CircuitSceneGraphRK8BlockPos ; BaseCircuitComponent::updateDependencies(CircuitSceneGraph &,BlockPos const&) 19 | .data.rel.ro:000000000AF088A8 dq offset _ZN20BaseCircuitComponent13allowIndirectEv ; BaseCircuitComponent::allowIndirect(void) 20 | 20 .data.rel.ro:000000000AF088B0 dq offset _ZN20BaseCircuitComponent11isHalfPulseEv ; BaseCircuitComponent::isHalfPulse(void) 21 | .data.rel.ro:000000000AF088B8 dq offset _ZN20BaseCircuitComponent9hasSourceERS_ ; BaseCircuitComponent::hasSource(BaseCircuitComponent&) 22 | .data.rel.ro:000000000AF088C0 dq offset _ZN20BaseCircuitComponent17hasChildrenSourceEv ; BaseCircuitComponent::hasChildrenSource(void) 23 | .data.rel.ro:000000000AF088C8 dq offset _ZN20BaseCircuitComponent18isSecondaryPoweredEv ; BaseCircuitComponent::isSecondaryPowered(void) -------------------------------------------------------------------------------- /src/component/BaseCircuitComponent.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_BASECIRCUITCOMPONENT_H 6 | #define MCBEREDSTONESYSTEM_BASECIRCUITCOMPONENT_H 7 | 8 | 9 | #include "CircuitComponentList.h" 10 | #include "CircuitTrackingInfo.h" 11 | 12 | class CircuitSystem; 13 | 14 | class CircuitSceneGraph; 15 | 16 | /* 17 | * 红石原件的抽象接口类 18 | */ 19 | class BaseCircuitComponent { 20 | public: 21 | CircuitComponentList mSources; //所有为该红石原件供能的信号源裂变 22 | bool mIgnoreFirstUpdate = false; 23 | bool mIsFirstTime = true; 24 | BlockPos mChunkPosition; 25 | int mStrength = 0; 26 | FACING mDirection = FACING::NOT_DEFINED; 27 | bool mAllowPowerUp = false; 28 | bool mAllowPowerDown = true; 29 | bool mRemoved = false; 30 | public: 31 | bool mShouldEvaluate = true; 32 | bool mNeedsUpdate = false; 33 | 34 | //vtb+2 35 | virtual int getStrength() const { 36 | return this->mStrength; 37 | } 38 | 39 | //vtb+3 40 | FACING getDirection() const { 41 | return this->mDirection; 42 | } 43 | 44 | //vtb+4 45 | virtual void setStrength(int strength) { 46 | this->mStrength = strength; 47 | } 48 | 49 | //vtb+5 50 | void setDirection(FACING facing) { 51 | this->mDirection = facing; 52 | } 53 | 54 | //vtb+6 55 | virtual bool consumePowerAnyDirection() { return false; } 56 | 57 | //vtb+7 58 | virtual bool canConsumerPower() { return false; } 59 | 60 | //vtb+8 61 | virtual bool canStopPower() { return false; } 62 | 63 | //vtb+9 64 | virtual void setStopPower(bool stop) {} 65 | 66 | //vtb+10 67 | virtual ComponentTypeID getBaseType() { 68 | return CSSC; 69 | } 70 | 71 | //vtb+11 72 | virtual ComponentTypeID getInstanceType() { 73 | return CSSC; 74 | } 75 | 76 | //vtb+12 77 | bool removeSource(const BlockPos &pos, BaseCircuitComponent *component); 78 | 79 | //vtb+13 80 | virtual bool addSource(CircuitSceneGraph *graph, CircuitTrackingInfo &info, int damping, bool &directPowered) {} 81 | 82 | //vtb+14 83 | virtual bool allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, bool &directPowered); 84 | 85 | //tvb+15 86 | virtual void checkLock(CircuitSystem &, BlockPos const &) {} 87 | 88 | //vtb+16 89 | virtual bool evaluate(CircuitSystem &, BlockPos const &) {} 90 | 91 | //vtb+17 92 | virtual void cacheValues(CircuitSystem &, const BlockPos &pos) {} 93 | 94 | //vtb+18 95 | virtual void updateDependencies(CircuitSceneGraph *graph, const BlockPos &pos) {} 96 | 97 | //vtb+19 98 | virtual bool allowIndirect() { return false; } 99 | 100 | //vtb+20 101 | virtual bool isHalfPulse() { 102 | return false; 103 | } 104 | 105 | //vtb+21 106 | bool hasSource(BaseCircuitComponent *component); 107 | 108 | 109 | //vtb+22 110 | virtual bool hasChildrenSource() { return false; } 111 | 112 | //vtb+23 113 | virtual bool isSecondaryPowered() { return false; } 114 | 115 | virtual bool hasDirectPower(); 116 | 117 | bool trackPowerSourceDuplicates(const CircuitTrackingInfo &info, int dampening, bool directlyPowered); 118 | 119 | bool canAllowPowerUp() const { 120 | return this->mAllowPowerUp; 121 | } 122 | 123 | bool canAllowPowerDown() const { return this->mAllowPowerDown; } 124 | 125 | 126 | void setRemoved() { 127 | this->mRemoved = true; 128 | } 129 | 130 | bool isRemoved() const { 131 | return this->mRemoved; 132 | } 133 | 134 | 135 | bool calculateValue(CircuitSystem *system); 136 | 137 | void clearFirstTimeFlag() { this->mIsFirstTime = false; } 138 | 139 | 140 | bool trackPowerSource(const CircuitTrackingInfo &info, int dampening, bool directlyPowered, int data); 141 | 142 | }; 143 | 144 | 145 | #endif //MCBEREDSTONESYSTEM_BASECIRCUITCOMPONENT_H 146 | -------------------------------------------------------------------------------- /src/CircuitSceneGraph.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/14. 3 | // 4 | 5 | #ifndef MCBEREDSTONESYSTEM_CIRCUITSCENEGRAPH_H 6 | #define MCBEREDSTONESYSTEM_CIRCUITSCENEGRAPH_H 7 | 8 | #include 9 | #include "mc/BlockPos.h" 10 | #include 11 | #include 12 | #include "component/BaseCircuitComponent.h" 13 | #include 14 | 15 | /* 16 | *这个类是整个红石系统构建的核心 17 | * 维护了所有的红石原件以及它们之间的相互关系 18 | * 以及何时对红石原件进行增删改以及进行信号源搜索 19 | */ 20 | class CircuitSceneGraph { 21 | //存了组件智能指针,裸指针和位置的entry 22 | struct PendingEntry { 23 | std::unique_ptr mComponent; 24 | BlockPos mPos; 25 | BaseCircuitComponent *mRawComponentPtr; 26 | }; 27 | //全局红石组件表 28 | /* 29 | *{ 30 | * pos1 --> {component1} 31 | * pos2-->{component2} 32 | * ... 33 | * pos n-->{component_n} 34 | * } 35 | */ 36 | std::unordered_map> mAllComponents; 37 | //活跃红石组件表,记载了所有的非充能方块的原件 38 | /* 39 | * {cmp1,cpm2,...cmp_n} 40 | */ 41 | CircuitComponentList mActiveComponents; 42 | //活跃的区块级别的元件表,记载了每个区块的所有非充能方块原件 43 | std::unordered_map mActiveComponentsPerChunk; 44 | 45 | //全局信号源-<消费者列表> 46 | /* 47 | * { 48 | * source_1-->{consumer_11,consumer_12,...} 49 | * ... 50 | * source_n-->{consumer_n1,....consumer_nm} 51 | * } 52 | */ 53 | std::unordered_map mPowerAssociationMap; 54 | //新加入电路的红石原件的一个buffer 55 | std::unordered_map mPendingAdds; 56 | //等待更新(这里的更新指的是进行信号源的重新搜索)的红石原件的buffer 57 | std::unordered_map mPendingUpdates; 58 | std::unordered_map> mComponentsToReEvaluate; 59 | 60 | //等待移除的列表 61 | std::vector mPendingRemoves; 62 | 63 | public: 64 | 65 | void add(const BlockPos &blockPos, std::unique_ptr component); 66 | 67 | BaseCircuitComponent *getComponent(const BlockPos &pos, ComponentTypeID id); 68 | 69 | BaseCircuitComponent *getBaseComponent(const BlockPos &pos); 70 | 71 | auto getFromPendingAdd(const BlockPos &p, ComponentTypeID typeId); 72 | 73 | 74 | CircuitComponentList &getComponents_FastIterationAcrossActive(void); 75 | 76 | auto getComponents_FastLookupByChunkPos() -> decltype(this->mActiveComponentsPerChunk); 77 | 78 | BaseCircuitComponent *getFromPendingAdd(const BlockPos &p); 79 | 80 | 81 | inline bool isPendingAdd(const BlockPos &p) { 82 | return this->mPendingAdds.find(p) != mPendingAdds.end(); 83 | } 84 | 85 | void preSetupPoweredBlocks(const ChunkPos &pos); 86 | 87 | void scheduleRelationshipUpdate(const BlockPos &pos, BaseCircuitComponent *component); 88 | 89 | void update(BlockSource *region); 90 | 91 | void remove(const BlockPos &pos, BaseCircuitComponent *pComponent); 92 | 93 | 94 | void removeComponent(const BlockPos &pos); 95 | 96 | void processPendingAdds(); 97 | 98 | void processPendingRemoves(); 99 | 100 | void processPendingUpdates(BlockSource *bs); 101 | 102 | void removeStaleRelationships(); 103 | 104 | void findRelationships(const BlockPos &pos, BaseCircuitComponent *pComponent, BlockSource *pSource); 105 | 106 | BaseCircuitComponent *addIfPoweredBlockAt(BlockSource *blockSource, const BlockPos &pos); 107 | 108 | void addPositionToReEvaluate(const ChunkPos &chunkPos, const BlockPos &pos); 109 | 110 | void searchForRelationshipsAboveAndBelow( 111 | CircuitComponentList &powerAssociationMap, 112 | BaseCircuitComponent *currentComponent, 113 | const BlockPos &targetPos, 114 | CircuitTrackingInfo &info, 115 | std::queue &stack 116 | ); 117 | 118 | void 119 | checkTransporterComponent(CircuitComponentList &powerAssociationMap, 120 | CircuitTrackingInfo &info, 121 | std::queue &queue, 122 | BlockPos &pos, 123 | FACING dir, 124 | bool goingDown); 125 | 126 | void 127 | checkBaseRailTransporterComponent(CircuitComponentList &powerAssociationMap, 128 | CircuitTrackingInfo &info, 129 | std::queue &queue, 130 | BlockPos &pos, 131 | FACING dir, 132 | bool goingDown); 133 | 134 | }; 135 | 136 | 137 | #endif //MCBEREDSTONESYSTEM_CIRCUITSCENEGRAPH_H 138 | -------------------------------------------------------------------------------- /src/component/BaseCircuitComponent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #include "BaseCircuitComponent.h" 6 | #include "../CircuitSystem.h" 7 | 8 | /** 9 | * 计算当前原件信号强度的基本算法 10 | * @param system 11 | * @return 12 | */ 13 | bool BaseCircuitComponent::calculateValue(CircuitSystem *system) { 14 | int newStrength = 0; 15 | //遍历所有红石原件 16 | //计算信号源强度 - 电阻 并取最大值 17 | for (auto &source: this->mSources.mComponents) { 18 | auto currentStrength = source.mComponent->getStrength() - source.mDampening; 19 | //如果信号源是半脉冲信号,就强制用15作为该信号源的强度 20 | if (source.mComponent->isHalfPulse()) 21 | currentStrength = 15 - source.mDampening; 22 | if (newStrength < currentStrength) 23 | newStrength = currentStrength; 24 | } 25 | 26 | bool hasChanged = this->mStrength != newStrength; 27 | this->mStrength = newStrength; 28 | return hasChanged || this->mIsFirstTime && this->mStrength == 0; 29 | } 30 | 31 | /* 32 | * 这个函数是被信号源搜索到并准备添加新的信号源的时候执行对当前信号源的相关信息进行修正, 33 | * data是描述连接的一种情况,比如中继器的描述的是 是从输入端进行输入还是锁存 34 | */ 35 | bool BaseCircuitComponent::trackPowerSource(const CircuitTrackingInfo &info, //NOLINT 36 | int dampening, bool directlyPowered, int data) { 37 | bool dampChanged = false; 38 | for (auto &s: this->mSources) { 39 | if (s.mPos == info.mPower.mPos) { 40 | /* old new 41 | * 1 0 42 | * 1 1 43 | * 0 0 44 | */ 45 | 46 | /* 47 | * 这里处理的目的是 48 | * 如果一个信号源通过多条线连到同一个消费者,这里有个问题就是 49 | * 由于搜索算法使用的BFS,那么**电阻更大的电路一定最后搜索到**, 50 | * 如果不加以处理就只能用电阻更大的值,这里显然不合理,因此才 51 | * 有这一段特判: 52 | * 每搜索完需要更新两个值: 53 | * 1. 电阻 54 | * 2. 是否是直接激活 55 | * 在不同的情况下对这俩值的设定有不同的策略 56 | */ 57 | //如果新搜索到的信号源在此之前已经是信号源了 58 | if (s.mDirectlyPowered || !directlyPowered) { 59 | //B. 其他情况 60 | // a. 激活情况不变 直接还是直接 非直接还是得直接 61 | // 使用电阻更小的情况,但是是否直接激活仍然用新的 62 | // 从直接激活 -> 非直接激活(这种情况好像不存在的样子) 63 | // 64 | if (s.mDampening <= info.mDampening) { 65 | //如果旧的电阻更小,保持不变 66 | dampChanged = false; 67 | } else { 68 | //新搜搜索到的电阻更小就更新 69 | s.mDampening = std::max(info.mDampening - 1, 0); // 70 | dampChanged = true; 71 | } 72 | } else { 73 | //A. 从非直接激活变成直接激活的情况 74 | //更新及活泼方式 75 | s.mDirectlyPowered = false; 76 | //旧的信号源强度不足以支撑这个原件(提供的能量为0),才使用 就青强制使用新旧电阻中更更小的一个 77 | if (info.mPower.mComponent && info.mPower.mComponent->getStrength() - info.mDampening <= 0) { 78 | s.mDampening = std::max(std::min(info.mDampening - 1, s.mDampening), 0); 79 | dampChanged = true; 80 | } else { 81 | //如果新的可以支撑就用新的 82 | s.mDampening = std::max(info.mDampening - 1, 0); 83 | dampChanged = true; 84 | } 85 | } 86 | 87 | return dampChanged; 88 | } 89 | } 90 | 91 | //新增加的信号源不在原有的信号源表内,直接把相关数据加入即可 92 | auto newDamp = std::max(0, dampening - 1); 93 | CircuitComponentList::Item it(info.mPower.mComponent, newDamp, info.mPower.mPos); 94 | it.mDirectlyPowered = directlyPowered; 95 | it.mData = data; 96 | this->mSources.push_back(it); 97 | return true; 98 | } 99 | 100 | /* 101 | * 允许搜索的过程中元件A能搜索到原件B 102 | */ 103 | bool BaseCircuitComponent::allowConnection(CircuitSceneGraph *pGraph, CircuitTrackingInfo &info, 104 | bool &directedPowered) {//NOLINT 105 | return true; 106 | } 107 | 108 | 109 | bool 110 | BaseCircuitComponent::trackPowerSourceDuplicates(const CircuitTrackingInfo &info, int dampening, bool directlyPowered) { 111 | //TODO 112 | return false; 113 | } 114 | 115 | /** 116 | * 为当前原件删除一个信号源 117 | * @param pos 118 | * @param component 119 | */ 120 | bool BaseCircuitComponent::removeSource(const BlockPos &pos, BaseCircuitComponent *component) { 121 | return this->mSources.removeSource(pos, component); 122 | } 123 | 124 | /* 125 | * `component`是否是当前原件的一个信号源 126 | */ 127 | bool BaseCircuitComponent::hasSource(BaseCircuitComponent *component) { //NOLINT 128 | if (this->mSources.size() <= 0)return false; 129 | for (auto &s: mSources.mComponents) { 130 | if (s.mComponent == component)return true; 131 | //信号源的信号源也算(前提是新仓元有子信号源) 132 | if (s.mComponent->hasChildrenSource() && s.mComponent->hasSource(component))return true; 133 | } 134 | return false; 135 | } 136 | 137 | /** 138 | * 是否有一个直接激活的信号源 139 | * @return 140 | */ 141 | bool BaseCircuitComponent::hasDirectPower() { 142 | for (auto &s: this->mSources) { //NOLINT 143 | if (s.mDirectlyPowered)return true; 144 | } 145 | return false; 146 | } 147 | 148 | 149 | -------------------------------------------------------------------------------- /src/CircuitSystem.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/2/23. 3 | // 4 | 5 | #include "CircuitSystem.h" 6 | 7 | /* 8 | * 给外部(Dimension对象)调用的接口 9 | */ 10 | void CircuitSystem::update(BlockSource *region) { 11 | this->mSceneGraph.update(region); 12 | this->mHasBeenEvaluated = false; 13 | } 14 | 15 | /* 16 | * 更新整个红石电路信号的总接口 17 | */ 18 | void CircuitSystem::evaluate(BlockSource *region) { 19 | this->_shouldEvaluate(region); 20 | this->cacheValues(); 21 | this->evaluateComponents(true); 22 | this->evaluateComponents(false); 23 | this->checkLocks(); 24 | this->mHasBeenEvaluated = true; 25 | } 26 | 27 | /* 28 | * 确定某个原件在下个红石刻是否需要更新, 29 | * 如果需要更新就把mShouldEvaluate这个值设为1 30 | */ 31 | void CircuitSystem::_shouldEvaluate(BlockSource *source) { 32 | if (!source)return; 33 | auto components = this->mSceneGraph.getComponents_FastLookupByChunkPos(); 34 | for (auto &item:components) { 35 | auto shouldEvaluate = source->areChunksFullyLoaded(item.first, 32); 36 | for (auto &comp:item.second) { 37 | if (comp.mComponent) { 38 | comp.mComponent->mShouldEvaluate = shouldEvaluate && !comp.mComponent->isRemoved(); 39 | } 40 | } 41 | } 42 | } 43 | 44 | /* 45 | * 电路中所有的红石原件计算新值并缓存的过程 46 | * 不是所有原件都会cacheValue,得看它们的具体实现 47 | */ 48 | void CircuitSystem::cacheValues() { 49 | auto compMap = this->mSceneGraph.getComponents_FastIterationAcrossActive(); 50 | for (auto &compItem:compMap) { 51 | auto component = compItem.mComponent; 52 | if (component->mShouldEvaluate) { 53 | component->cacheValues(*this, compItem.mPos); 54 | } 55 | } 56 | } 57 | 58 | /* 59 | * 锁检查 60 | * 只对红石中继器有效 61 | */ 62 | void CircuitSystem::checkLocks() { 63 | auto compMap = this->mSceneGraph.getComponents_FastIterationAcrossActive(); 64 | for (auto &compItem:compMap) { 65 | auto component = compItem.mComponent; 66 | if (component->mShouldEvaluate) { 67 | component->checkLock(*this, compItem.mPos); 68 | } 69 | } 70 | } 71 | 72 | /* 73 | * 更新实际信号值的过程 74 | * 或者叫同步新值和旧值的过程 75 | * 每个红石刻生产者和非生产者分别进行 76 | */ 77 | void CircuitSystem::evaluateComponents(bool bOnlyProducers) { 78 | auto compMap = this->mSceneGraph.getComponents_FastIterationAcrossActive(); 79 | for (auto &compItem:compMap) { 80 | auto component = compItem.mComponent; 81 | auto typeID = component->getBaseType(); 82 | if (component->mShouldEvaluate) { 83 | auto typeFilter = typeID == CSPC || typeID == CSCA; 84 | if (typeFilter == bOnlyProducers) { 85 | component->evaluate(*this, compItem.mPos); 86 | component->mNeedsUpdate = true; 87 | } 88 | } 89 | } 90 | } 91 | 92 | FACING CircuitSystem::getDirection(const BlockPos &pos) { 93 | auto component = this->mSceneGraph.getBaseComponent(pos); 94 | return component ? component->getDirection() : FACING::NOT_DEFINED; 95 | } 96 | 97 | int CircuitSystem::getStrength(const BlockPos &pos) { 98 | auto component = this->mSceneGraph.getBaseComponent(pos); 99 | return component ? component->getStrength() : -1; 100 | } 101 | 102 | bool CircuitSystem::hasDirectPower(const BlockPos &pos) { 103 | auto component = this->mSceneGraph.getBaseComponent(pos); 104 | return component != nullptr && component->hasDirectPower(); 105 | } 106 | 107 | bool CircuitSystem::invalidatePos(const BlockPos &pos) { 108 | //todo 109 | } 110 | 111 | bool CircuitSystem::isAvailableAt(const BlockPos &pos) { 112 | return this->mSceneGraph.getBaseComponent(pos) != nullptr; 113 | } 114 | 115 | void CircuitSystem::preSetupPoweredBlocks(const ChunkPos &pos) { 116 | //todo 117 | } 118 | 119 | 120 | void CircuitSystem::removeComponents(const BlockPos &pos) { 121 | //电路图没有锁住才移除 122 | if (!this->mLockGraph) { 123 | auto component = this->mSceneGraph.getBaseComponent(pos); 124 | this->mSceneGraph.remove(pos, component); 125 | } 126 | } 127 | 128 | void CircuitSystem::setStrength(const BlockPos &pos, int strength) { 129 | auto component = this->mSceneGraph.getBaseComponent(pos); 130 | if (component) 131 | component->setStrength(strength); 132 | } 133 | 134 | void CircuitSystem::updateDependencies(BlockSource *blockSource) { 135 | this->mSceneGraph.update(blockSource); 136 | this->mHasBeenEvaluated = false; 137 | } 138 | 139 | /* 140 | * 创建一个红石原件 141 | * 玩家放置一个红石相关的方块的时候会直接触发这个函数(其实上层还有一个泛型函数) 142 | * @pos 方块位置 143 | * @direction 方块方向(特殊值) 144 | * @newComponent 创建的红石组件(由上层泛型函数创建) 145 | */ 146 | BaseCircuitComponent *CircuitSystem::createComponent(const BlockPos &pos, FACING direction, 147 | std::unique_ptr newComponent) { 148 | auto component = newComponent.get(); 149 | //设置方向 150 | component->setDirection(direction); 151 | //如果当前电路是锁上的就加入失败,返回空指针 152 | if (this->mLockGraph) { 153 | newComponent.reset(component); 154 | return nullptr; 155 | } else { 156 | //没锁上就把新的组件传给@SceneGraph 157 | this->mSceneGraph.add(pos, std::move(newComponent)); 158 | //返回裸指针作为句柄进行后续处理 159 | return this->mSceneGraph.getFromPendingAdd(pos); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/mc/BlockPos.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2020/10/22. 3 | // 4 | 5 | #include "BlockPos.h" 6 | #include 7 | #include 8 | 9 | bool BlockPos::operator==(const BlockPos &v) const { 10 | return x == v.x && y == v.y && z == v.z; 11 | } 12 | 13 | bool BlockPos::operator!=(const BlockPos &v) const { 14 | return x != v.x || y != v.y || z != v.z; 15 | } 16 | 17 | float BlockPos::distanceTo(const BlockPos &blockPos) const { 18 | return (float) sqrt((blockPos.x - x) * (blockPos.x - x) + 19 | (blockPos.y - y) * (blockPos.y - y) + 20 | (blockPos.z - z) * (blockPos.z - z)); 21 | } 22 | 23 | std::ostream &operator<<(std::ostream &os, const BlockPos &vec3) { 24 | os << "[" << vec3.x << "," << vec3.y << "," << vec3.z << "]"; 25 | return os; 26 | } 27 | 28 | 29 | std::string BlockPos::toString() const { 30 | return "[" 31 | + std::to_string(x) + "," 32 | + std::to_string(y) + "," 33 | + std::to_string(z) + "]"; 34 | } 35 | 36 | std::vector BlockPos::getNeighbourPos() { 37 | return { 38 | {x + 1, y, z}, 39 | {x - 1, y, z}, 40 | {x, y + 1, z}, 41 | {x, y - 1, z}, 42 | {x, y, z + 1}, 43 | {x, y, z - 1} 44 | }; 45 | } 46 | 47 | std::vector BlockPos::getPlainNeighbourPos() { 48 | return { 49 | {x + 1, y, z}, 50 | {x - 1, y, z}, 51 | {x, y, z + 1}, 52 | {x, y, z - 1} 53 | }; 54 | } 55 | 56 | BlockPos2 BlockPos::InChunkOffset() const { 57 | auto newX = x % 16; 58 | auto newZ = z % 16; 59 | if (newX < 0)newX += 16; 60 | if (newZ < 0)newZ += 16; 61 | return {newX, newZ}; 62 | } 63 | 64 | BlockPos2 BlockPos::toChunkPos() const { 65 | auto cx = x < 0 ? x - 15 : x; 66 | auto cz = z < 0 ? z - 15 : z; 67 | return {cx / 16, cz / 16}; 68 | } 69 | 70 | bool BlockPos::operator<(const BlockPos &rhs) const { 71 | if (x < rhs.x) 72 | return true; 73 | if (rhs.x < x) 74 | return false; 75 | if (y < rhs.y) 76 | return true; 77 | if (rhs.y < y) 78 | return false; 79 | return z < rhs.z; 80 | } 81 | 82 | int BlockPos::operator*(const BlockPos &pos) const { 83 | return this->x * pos.x + this->y * pos.y + this->z * pos.z; 84 | } 85 | 86 | BlockPos BlockPos::operator+(const BlockPos &pos) const { 87 | return {x + pos.x, y + pos.y, z + pos.z}; 88 | } 89 | 90 | 91 | std::string BlockPos2::toString() const { 92 | return "[" 93 | + std::to_string(x) + "," 94 | + std::to_string(z) + "]"; 95 | } 96 | 97 | 98 | bool BlockPos2::isSlimeChunk() const { 99 | auto seed = (x * 0x1f1f1f1fu) ^(uint32_t) z; 100 | std::mt19937 mt(seed); 101 | return mt() % 10 == 0; 102 | } 103 | 104 | bool BlockPos2::operator<(const BlockPos2 &rhs) const { 105 | if (x < rhs.x) 106 | return true; 107 | if (rhs.x < x) 108 | return false; 109 | return z < rhs.z; 110 | } 111 | 112 | std::string facingToString(FACING facing) { 113 | switch (facing) { 114 | case FACING::POS_X: 115 | return "+x"; 116 | case FACING::NEG_X: 117 | return "-x"; 118 | case FACING::POS_Y: 119 | return "+y"; 120 | case FACING::POS_Z: 121 | return "+z"; 122 | case FACING::NEG_Y: 123 | return "-y"; 124 | case FACING::NEG_Z: 125 | return "-z"; 126 | default: 127 | return "unknown"; 128 | } 129 | } 130 | 131 | std::string facingToDirString(FACING facing) { 132 | switch (facing) { 133 | case FACING::POS_X: 134 | return "west"; 135 | case FACING::NEG_X: 136 | return "east"; 137 | case FACING::POS_Y: 138 | return "up"; 139 | case FACING::POS_Z: 140 | return "south"; 141 | case FACING::NEG_Y: 142 | return "down"; 143 | case FACING::NEG_Z: 144 | return "north"; 145 | default: 146 | return "unknown"; 147 | } 148 | } 149 | 150 | BlockPos facingToBlockPos(FACING facing) { 151 | switch (facing) { 152 | case FACING::NEG_Y: 153 | return {0, -1, 0}; 154 | case FACING::POS_Y: 155 | return {0, 1, 0}; 156 | case FACING::NEG_Z: 157 | return {0, 0, -1}; 158 | case FACING::POS_Z: 159 | return {0, 0, 1}; 160 | case FACING::NEG_X: 161 | return {-1, 0, 0}; 162 | case FACING::POS_X: 163 | return {1, 0, 0}; 164 | } 165 | return {0, 0, 0}; 166 | } 167 | 168 | bool facingIsPos(FACING facing) { 169 | return facing == FACING::POS_X || facing == FACING::POS_Y || facing == FACING::POS_Z; 170 | } 171 | 172 | bool facingIsNeg(FACING facing) { 173 | return facing == FACING::NEG_X || facing == FACING::NEG_Y || facing == FACING::NEG_Z; 174 | } 175 | 176 | bool facingIsX(FACING facing) { 177 | return facing == FACING::POS_X || facing == FACING::NEG_X; 178 | } 179 | 180 | bool facingIsY(FACING facing) { 181 | return facing == FACING::POS_Y || facing == FACING::NEG_Y; 182 | } 183 | 184 | bool facingIsZ(FACING facing) { 185 | return facing == FACING::POS_Z || facing == FACING::NEG_Z; 186 | } 187 | 188 | FACING invFacing(FACING facing) { 189 | switch (facing) { 190 | case FACING::NEG_Y: 191 | return FACING::POS_Y; 192 | case FACING::POS_Y: 193 | return FACING::NEG_Y; 194 | case FACING::NEG_Z: 195 | return FACING::POS_Z; 196 | case FACING::POS_Z: 197 | return FACING::NEG_Z; 198 | case FACING::NEG_X: 199 | return FACING::POS_X; 200 | case FACING::POS_X: 201 | return FACING::NEG_X; 202 | default: 203 | return FACING::POS_X; 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /src/CircuitSceneGraph.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2021/3/14. 3 | // 4 | 5 | #include "CircuitSceneGraph.h" 6 | #include 7 | #include 8 | #include "component/powered_block/PoweredBlockComponent.h" 9 | 10 | namespace { 11 | 12 | 13 | /** 14 | * 把新的消费者加入队列 15 | * 这个递归的细节真的不想看了,告辞 16 | * @param graph 电路图 17 | * @param powerAssociationMap 当前发起搜索的红石信号源目前拥有的消费者 18 | * @param newComponent 新的消费者 19 | * @param info 递归信息 20 | * @param newPos 21 | * @param face 22 | * @param queue 23 | */ 24 | void addToFillQueue(CircuitSceneGraph *graph, //电路图对象 25 | CircuitComponentList &powerAssociationMap, //正在进行搜索的信号源所支撑的原件表 26 | BaseCircuitComponent *newComponent, //正在被搜索的原件 27 | CircuitTrackingInfo &info, //track info 28 | const BlockPos &newPos, //被搜索的原件位置 29 | FACING face, //nearest -> 被搜索原件的方向 30 | std::queue &queue //队列 31 | ) { 32 | auto newInfo = info; 33 | //把当前被搜索的原件放到current位置 34 | initEntry(newInfo.mCurrent, newComponent, newPos); 35 | 36 | auto newDampening = info.mDampening; 37 | auto bDirectlyPowered = info.mDirectlyPowered; 38 | 39 | //提前就更新映射表的图? 40 | powerAssociationMap.mComponents.emplace_back(newComponent, 0, newPos); 41 | 42 | 43 | //如果nearest允许连接 44 | if (info.mNearest.mComponent->allowConnection(graph, newInfo, bDirectlyPowered)) { 45 | //把信号源加入找到的消费者的信号源列表中里面 46 | //尝试添加成功 47 | if (newComponent->addSource(graph, newInfo, newDampening, bDirectlyPowered)) { 48 | //更新track信息 49 | //2nd <- near 50 | //near <- cur 51 | newInfo.m2ndNearest = info.mNearest; 52 | initEntry(newInfo.mNearest, newComponent, newPos); 53 | newInfo.mDampening = newDampening; 54 | newInfo.mDirectlyPowered = bDirectlyPowered; 55 | //队列中插入新的的信息 56 | queue.push(newInfo); 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * 搜索消费者 63 | * BFS递归过程 64 | * @param bs 句柄 65 | * @param powerAssociationMap 当前消费者列表 66 | * @param graph 全局电路图对象 67 | * @param trackInfo //递归信息 68 | * @param facing //朝向 69 | * @param pos //位置 70 | * @param stack //队列 71 | */ 72 | void searchForRelationshipAt(BlockSource *bs, CircuitComponentList &powerAssociationMap, CircuitSceneGraph *graph, 73 | CircuitTrackingInfo &trackInfo, FACING facing, 74 | const BlockPos &pos, //IDA中没有这个参数,但是加上更合理 75 | std::queue &queue) { 76 | auto newPos = pos + facingToBlockPos(facing); 77 | 78 | 79 | auto newComponent = graph->getBaseComponent(newPos); 80 | //新方块加入队列 81 | if (pos != trackInfo.mNearest.mPos && pos != trackInfo.m2ndNearest.mPos) { 82 | addToFillQueue(graph, powerAssociationMap, newComponent, trackInfo, newPos, facing, queue); 83 | } 84 | } 85 | 86 | } 87 | 88 | /* 89 | * 玩家放下红石相关方块后会触发这个函数 90 | * @BlockPos 方块的坐标 91 | * @component 红石组件 这个是由@CircuitSysttem 传递过来的参数 92 | * @return 无 93 | * 94 | * 这个函数只有部分情况会直接把新的组件加入pendingAdd列表中 95 | * - 目前不知道这么写的意义是什么 96 | * - 如果有这个方块且是充能方块不加入 97 | * - 其他情况都加入 98 | */ 99 | void CircuitSceneGraph::add(const BlockPos &blockPos, std::unique_ptr component) { 100 | auto iter = this->mPendingAdds.find(blockPos); 101 | auto &pending = iter->second; 102 | //如果当前的add列表有这个方块且这个组件的类型是充能方块 103 | if (iter != mPendingAdds.end() && iter->second.mComponent->getBaseType() == CSPB) { 104 | if (pending.mComponent->canAllowPowerUp()) { 105 | return; 106 | } else { 107 | pending.mComponent.reset(component.get()); 108 | } 109 | //没有这个方块或者有但不是充能方块 110 | } else { 111 | PendingEntry pendingEntry; 112 | pendingEntry.mComponent.reset(component.get()); 113 | pendingEntry.mPos = blockPos; 114 | this->mPendingAdds[blockPos] = std::move(pendingEntry); 115 | } 116 | 117 | if (component->canAllowPowerUp()) { 118 | pending.mComponent.reset(nullptr); 119 | pending.mComponent = std::move(component); 120 | } 121 | } 122 | 123 | /** 124 | * 从全局元件表中获取特定位置的原件 125 | * @param pos 位置 126 | * @return 原件的指针 127 | */ 128 | BaseCircuitComponent *CircuitSceneGraph::getBaseComponent(const BlockPos &pos) { 129 | auto iter = this->mAllComponents.find(pos); 130 | if (iter == mAllComponents.end() || iter->second->isRemoved()) { 131 | return nullptr; 132 | } 133 | return iter->second.get(); 134 | } 135 | 136 | /** 137 | * 从全局元件表获取指定位置指定类型的原件 138 | * @param pos 位置 139 | * @param id 类型 140 | * @return 返回原该原件的指针 141 | */ 142 | BaseCircuitComponent *CircuitSceneGraph::getComponent(const BlockPos &pos, ComponentTypeID id) { 143 | auto comp = this->getBaseComponent(pos); 144 | return comp->getBaseType() == id ? comp : nullptr; 145 | } 146 | 147 | CircuitComponentList &CircuitSceneGraph::getComponents_FastIterationAcrossActive() { 148 | return this->mActiveComponents; 149 | } 150 | 151 | auto CircuitSceneGraph::getComponents_FastLookupByChunkPos() -> decltype(this->mActiveComponentsPerChunk) { 152 | return this->mActiveComponentsPerChunk; 153 | } 154 | 155 | BaseCircuitComponent *CircuitSceneGraph::getFromPendingAdd(const BlockPos &p) { 156 | auto iter = this->mPendingAdds.find(p); 157 | return iter != mPendingAdds.end() ? iter->second.mComponent.get() : nullptr; 158 | } 159 | 160 | auto CircuitSceneGraph::getFromPendingAdd(const BlockPos &p, ComponentTypeID id) { 161 | auto comp = this->getFromPendingAdd(p); 162 | return comp->getBaseType() == id ? comp : nullptr; 163 | } 164 | 165 | void CircuitSceneGraph::preSetupPoweredBlocks(const ChunkPos &pos) { 166 | BlockPos blockPos(pos.x << 4, 0, pos.z << 4); 167 | auto chunkPosIter = this->mComponentsToReEvaluate.find(blockPos); 168 | if (chunkPosIter != mComponentsToReEvaluate.end()) { 169 | auto &blocks = chunkPosIter->second; 170 | for (auto &block: blocks) { 171 | auto comp = this->getBaseComponent(block); 172 | this->scheduleRelationshipUpdate(block, comp); 173 | } 174 | this->mComponentsToReEvaluate.erase(chunkPosIter); 175 | } 176 | } 177 | 178 | /* 179 | * 更新原件component的电路连接状态 180 | * @pos 原件位置 181 | * @component 原件自身(这个元件只能是生产者或者电容器,不可能是消费者) 182 | * 这个函数的作用就是从自身出发,寻找自己能够提供能量的红石原件, 183 | */ 184 | void CircuitSceneGraph::scheduleRelationshipUpdate(const BlockPos &pos, BaseCircuitComponent *component) { 185 | if (!component) return; 186 | auto typeID = component->getBaseType(); 187 | //只有生产者和电容器才能作为信号源来提供能量 188 | if (typeID == CSCA || typeID == CSPB) { 189 | PendingEntry entry = {std::unique_ptr(component), pos, component}; 190 | //加入待更新列表 191 | this->mPendingUpdates.insert({pos, std::move(entry)}); 192 | } 193 | } 194 | 195 | void CircuitSceneGraph::update(BlockSource *pSource) { 196 | this->processPendingRemoves(); 197 | this->processPendingAdds(); 198 | this->processPendingUpdates(pSource); 199 | } 200 | 201 | void CircuitSceneGraph::remove(const BlockPos &pos, BaseCircuitComponent *component) { 202 | //从等待加入的列表中移除,防止被重新加入 203 | this->mPendingAdds.erase(pos); 204 | if (component) { 205 | //标记为已经移除 206 | component->setRemoved(); 207 | //加入待移除列表 208 | this->mPendingRemoves.emplace_back(component, pos, component); 209 | } 210 | } 211 | 212 | 213 | //把pend ing列表中的红石组件正式加入到电路中 214 | void CircuitSceneGraph::processPendingAdds() { 215 | for (auto iter = this->mPendingAdds.begin();; iter = this->mPendingAdds.erase(iter)) { 216 | //遍历pendingAdd列表,找到一个删去一个 217 | if (iter == mPendingAdds.end())break; 218 | //下面是具体行为 219 | //取出一个entry 220 | auto &pendingToAdd = iter->second; 221 | //pending中存的组件对象 222 | //在全局元件表中寻找这个等待加入的原件 223 | auto componentGroupIter = this->mAllComponents.find(pendingToAdd.mPos); 224 | 225 | bool flagV19 = false; 226 | bool needProcess = true; 227 | if (componentGroupIter != mAllComponents.end() && componentGroupIter->second) { 228 | //如果在全局元件表中找到了这个等待加入的原件 229 | //如果找到的这个已存在的原件不是空指针 230 | if (componentGroupIter->second->getBaseType() == CSPB) { 231 | flagV19 = pendingToAdd.mComponent->getBaseType() != CSPB; 232 | } 233 | } 234 | 235 | //如果没找到自然需要处理,因此needProcess默认是true 236 | //如果找到了也有一种需要处理的情况: 237 | // 就是当前原件是充能方块且等待加入的不是充能方块 238 | if (componentGroupIter != mAllComponents.end()) { 239 | needProcess = flagV19; 240 | } 241 | if (!needProcess)return; 242 | //下面开始正式地处理 243 | if (flagV19) { 244 | //这里是对充能方块的特判的情况 245 | auto allIter = this->mAllComponents.begin(); 246 | while (allIter != this->mAllComponents.end()) { 247 | //遍历当前所有组件,如果有个组件的信号源是充能方块就把这个方块移除 248 | if (allIter->second->hasSource(componentGroupIter->second.get())) { 249 | allIter->second->removeSource(componentGroupIter->first, componentGroupIter->second.get()); 250 | } 251 | ++allIter; 252 | } 253 | this->mAllComponents.erase(componentGroupIter); 254 | } 255 | //下面是所有方块都需要的情况,正式把pending列表中的组件加入红石电路中 256 | //把pd原件加入全局红石组件表 257 | auto component = pendingToAdd.mComponent.get(); 258 | this->mAllComponents.insert({pendingToAdd.mPos, std::move(pendingToAdd.mComponent)}); 259 | auto typeID = component->getBaseType(); 260 | //如果新加入的组件不是充能方块 261 | if (typeID != CSPB) { 262 | //如果不是充能方块就加入活跃元件表和活跃区块元件表 263 | this->mActiveComponents.mComponents.emplace_back(component, 0, pendingToAdd.mPos); 264 | this->mActiveComponentsPerChunk[component->mChunkPosition].mComponents.emplace_back(component, 0, 265 | pendingToAdd.mPos); 266 | } 267 | //如果新加入的方块是生产者 268 | if (typeID == CSPC) { 269 | //重新构建电路,更新信号源和寻找依赖 270 | this->scheduleRelationshipUpdate(pendingToAdd.mPos, component); 271 | } else if (typeID == CSCA) { 272 | //重新构建电路,更新信号源和寻找依赖 273 | this->scheduleRelationshipUpdate(pendingToAdd.mPos, component); 274 | for (int c1 = -1; c1 <= 1; c1 += 2) { 275 | for (int c2 = -1; c2 <= 1; c2 += 2) { 276 | //获取四个角的方块 277 | //如果四角是电容器这四个角的方块也更新下 278 | auto pos = pendingToAdd.mPos + BlockPos(c1, 0, c2); 279 | auto possibleComponent = this->getBaseComponent(pos); 280 | if (possibleComponent && possibleComponent->getBaseType() == CSCA) { 281 | this->scheduleRelationshipUpdate(pos, possibleComponent); 282 | } 283 | } 284 | } 285 | } 286 | 287 | for (int y = -1; y < 1; y++) { 288 | for (int face = 0; face < 6; face++) { 289 | //获取竖直方向上的两个方块的六面所有方块 290 | auto pos = pendingToAdd.mPos + BlockPos(0, y, 0) + facingToBlockPos((FACING) face); 291 | auto possibleComponent = this->getBaseComponent(pos); 292 | if (possibleComponent) { 293 | auto tID = possibleComponent->getBaseType(); 294 | if (tID != CSPC && tID != CSCA) { 295 | for (auto item: possibleComponent->mSources) { 296 | this->scheduleRelationshipUpdate(item.mPos, item.mComponent); 297 | } 298 | } else { 299 | this->scheduleRelationshipUpdate(pos, possibleComponent); 300 | } 301 | } 302 | } 303 | } 304 | } 305 | } 306 | 307 | //从pending列表中取出等待移除的组件,将其从红石电路中移除 308 | void CircuitSceneGraph::processPendingRemoves() { 309 | //遍历等待移除的列表,进行真正的移除操作 310 | for (auto &compEntry: this->mPendingRemoves) { 311 | this->removeComponent(compEntry.mPos); 312 | } 313 | this->mPendingRemoves.clear(); 314 | } 315 | 316 | /* 317 | * 集中处理需要更新信号源的原件(仅包括生产者和电容器,这个列表不会包含消费者) 318 | * @bs BlockSource 319 | */ 320 | void CircuitSceneGraph::processPendingUpdates(BlockSource *bs) { 321 | if (this->mPendingUpdates.empty())return; 322 | //移待更新方块的消费者 323 | this->removeStaleRelationships(); 324 | auto iter = this->mPendingUpdates.begin(); 325 | //遍历整个待更新列表,寻找信号源-消费者关系 326 | while (iter != this->mPendingUpdates.end()) { 327 | if (iter->second.mRawComponentPtr) { 328 | this->findRelationships(iter->second.mPos, iter->second.mRawComponentPtr, bs); 329 | } 330 | iter = this->mPendingUpdates.erase(iter); 331 | } 332 | 333 | //遍历所有原件并更新依赖 334 | for (auto &component: this->mAllComponents) { 335 | //更新依赖 336 | //这个函数只有电容器才具有实际行为(包括红石火把,比较器和中继器) 337 | component.second->updateDependencies(this, component.first); 338 | } 339 | } 340 | 341 | //移除稳定的关系 342 | void CircuitSceneGraph::removeStaleRelationships() { 343 | for (auto &pendingItem: this->mPendingUpdates) { 344 | auto updatePos = pendingItem.second.mPos; 345 | //在全局电源关系图中找到该方块充当信号源的关系图 346 | auto powerAssociationIter = this->mPowerAssociationMap.find(updatePos); 347 | if (powerAssociationIter != this->mPowerAssociationMap.end()) { 348 | //如果找到了 349 | auto relationships = powerAssociationIter->second; 350 | for (auto reIter = relationships.begin(); reIter != relationships.end(); ++reIter) { 351 | //遍历它们的每一个消费者 352 | auto iter = this->mAllComponents.find(reIter->mPos); 353 | if (iter != mAllComponents.end()) { 354 | //消费者移除指向这个待更新方块的信号源 355 | iter->second->removeSource(updatePos, pendingItem.second.mRawComponentPtr); 356 | relationships.mComponents.erase(reIter); 357 | } else { 358 | ++reIter; 359 | } 360 | } 361 | } 362 | } 363 | } 364 | 365 | 366 | /* 367 | * 这个函数是真的给生产者寻找自己能提供能量的消费者的函数 368 | * @pos,生产者的位置 369 | * @producerTarget 生产者本身(包括电容器) 370 | */ 371 | void 372 | CircuitSceneGraph::findRelationships(const BlockPos &pos, BaseCircuitComponent *producerTarget, BlockSource *pSource) { 373 | //在这里更新电路连接 374 | 375 | auto powerAssociationIter = this->mPowerAssociationMap.find(pos); 376 | //信号源列表没有这个信号源就加入 377 | if (powerAssociationIter == mPowerAssociationMap.end()) { 378 | this->mPowerAssociationMap.insert({pos, CircuitComponentList()}); 379 | } 380 | // //在信号源列表中找到这个信号源,前面刚插入,这里不可能没有,因为mc是单线程的 381 | // auto sourceIter = this->mPowerAssociationMap.find(pos); 382 | // assert(sourceIter != mPowerAssociationMap.end()); 383 | 384 | 385 | std::queue queue; 386 | //创建一个初始的信息,距离是0,Entry内的4个entry都是当前生产者 387 | //info内的信息 (power->...->2ndNear->near->cur) 388 | CircuitTrackingInfo startInfo(producerTarget, pos, 0); 389 | 390 | 391 | //开始做BFS 392 | //队列中加入这个信号源 393 | queue.push(startInfo); 394 | do { 395 | 396 | //典型的BFS结构 397 | auto fillTrack = queue.front(); 398 | queue.pop(); 399 | //取出队列首部元素 400 | auto targetPos = fillTrack.mNearest.mPos; 401 | 402 | auto currentComponent = fillTrack.mNearest.mComponent; //这里暂时不知道为啥要用Nearest 403 | if (currentComponent) { 404 | int damping = fillTrack.mDampening; 405 | auto dir = fillTrack.mNearest.mComponent->getDirection(); 406 | //所有操作都要在damping在15格以内 407 | if (damping <= 15) { 408 | 409 | 410 | /*这里是搜索充能方块并加入更新表*/ 411 | if (currentComponent->getBaseType() != CSPB) { //如果不是充能方块 412 | for (auto facing = 0; facing < 6; facing++) { 413 | //遍历六面的方块位置 414 | auto newPos = targetPos + facingToBlockPos(static_cast(facing)); 415 | 416 | //如果当前电路中没有这个红石原件,这就是说明搜索到充能方块了 417 | if (!this->getBaseComponent(newPos) && pSource) { 418 | //猜测意思是区块已经加载,就更新充能方块信息 419 | if (pSource->hasChunksAt(newPos, 0)) { 420 | this->addIfPoweredBlockAt(pSource, newPos); 421 | } else { 422 | //如果区块没加载,就暂存等后面加载 423 | ChunkPos chunkPos = newPos.toChunkPos(); 424 | this->addPositionToReEvaluate(chunkPos, targetPos); 425 | } 426 | } 427 | } 428 | } 429 | 430 | 431 | 432 | //这里是实际的电路构建连接 433 | for (auto face = 0; face < 6; face++) { 434 | searchForRelationshipAt(pSource, powerAssociationIter->second, this, fillTrack, 435 | static_cast(face), targetPos, queue); 436 | } 437 | 438 | //搜索上下方向的关系? 439 | this->searchForRelationshipsAboveAndBelow(powerAssociationIter->second, 440 | currentComponent, 441 | pos, 442 | startInfo, 443 | queue 444 | ); 445 | } 446 | } 447 | 448 | } while (!queue.empty()); 449 | 450 | } 451 | 452 | 453 | /** 454 | * 尝试把方块作为充能方块加入红石电路 455 | * @param blockSource 方块源 456 | * @param pos 坐标 457 | */ 458 | BaseCircuitComponent *CircuitSceneGraph::addIfPoweredBlockAt(BlockSource *blockSource, const BlockPos &pos) { 459 | //check block property and solid and so on 460 | auto powerBlockComponent = std::make_unique(); 461 | this->mAllComponents.insert({pos, std::move(powerBlockComponent)}); 462 | //set allow as power source 463 | //if property & 0x800000>0 set allow power up 464 | //??why stack memory 465 | return powerBlockComponent.get(); 466 | } 467 | 468 | /** 469 | * 把位置加到重新计算列表 470 | * @param chunkPos(区块坐标) 471 | * @param pos (具体位置) 472 | */ 473 | void CircuitSceneGraph::addPositionToReEvaluate(const ChunkPos &chunkPos, const BlockPos &pos) { 474 | BlockPos p = {chunkPos.x << 4, 0, chunkPos.z << 4}; 475 | this->mComponentsToReEvaluate[p].push_back(pos); 476 | } 477 | 478 | //把原件从电路中移除的实际操作 479 | //从各种表中移除原件并更新电路连接 480 | void CircuitSceneGraph::removeComponent(const BlockPos &pos) { 481 | //全局元件表中查找这个原件,找不到直接返回 482 | auto componentGroupIter = this->mAllComponents.find(pos); 483 | if (componentGroupIter == mAllComponents.end())return; 484 | //找到了进行具体操作 485 | //从全局元件表中移除 486 | this->mAllComponents.erase(pos); 487 | auto component = componentGroupIter->second.get(); 488 | //如果不是充能方块就把这个方块从信号激活图中移除 489 | if (component->getBaseType() != CSPB) { 490 | this->mPowerAssociationMap.erase(pos); 491 | } 492 | 493 | //从区块活跃元件表中移除 494 | for (auto &item: this->mActiveComponentsPerChunk) { 495 | item.second.removeSource(pos, component); 496 | } 497 | 498 | auto sources = component->mSources; 499 | for (auto &item: sources.mComponents) { 500 | auto updateComponent = item.mComponent; 501 | //重新计算这个原件的所有连接的原件 502 | this->scheduleRelationshipUpdate(item.mPos, item.mComponent); 503 | } 504 | 505 | //再次遍历全局元件表,删除相关依赖 506 | for (auto &allComp: this->mAllComponents) { 507 | auto updateComponent = allComp.second.get(); 508 | updateComponent->removeSource(pos, component); 509 | auto iter = updateComponent->mSources.mComponents.begin(); 510 | while (iter != updateComponent->mSources.mComponents.end()) { 511 | if (iter->mPos == pos || iter->mComponent == component) { 512 | this->scheduleRelationshipUpdate(allComp.first, updateComponent); 513 | } else { 514 | ++iter; 515 | } 516 | } 517 | 518 | } 519 | 520 | //更新六个方向的所有红石组件以及它们的信号源 521 | for (int face = 0; face < 6; ++face) { 522 | auto position = pos + facingToBlockPos((FACING) face); 523 | auto updateComponent = this->getBaseComponent(position); 524 | if (updateComponent) { 525 | this->scheduleRelationshipUpdate(pos, updateComponent); 526 | for (auto &item: updateComponent->mSources.mComponents) { 527 | this->scheduleRelationshipUpdate(item.mPos, item.mComponent); 528 | } 529 | } 530 | } 531 | 532 | this->mPendingUpdates.erase(pos); 533 | componentGroupIter->second.reset(nullptr); 534 | } 535 | 536 | void CircuitSceneGraph::searchForRelationshipsAboveAndBelow(CircuitComponentList &powerAssociationMap, 537 | BaseCircuitComponent *currentComponent, 538 | const BlockPos &targetPos, 539 | CircuitTrackingInfo &info, 540 | std::queue &stack) { 541 | auto typeID = currentComponent->getBaseType(); 542 | if (typeID == CSPB) { 543 | auto otherPos = targetPos + facingToBlockPos(POS_Y); 544 | //获取上方的充能方块 545 | auto up = this->getComponent(otherPos, CSPB); 546 | if (!up || up->canAllowPowerUp()) { 547 | for (auto facing = 2; facing <= 5; facing++) { 548 | checkTransporterComponent(powerAssociationMap, info, stack, otherPos, static_cast(facing), 549 | false); 550 | } 551 | } 552 | otherPos = targetPos + facingToBlockPos(NEG_Y); 553 | auto down = this->getComponent(otherPos, CSPB); 554 | if (!down || down->canAllowPowerUp()) { 555 | for (auto facing = 2; facing <= 5; facing++) { 556 | checkTransporterComponent(powerAssociationMap, info, stack, otherPos, static_cast(facing), 557 | false); 558 | } 559 | } 560 | } else if (typeID != CSPC || currentComponent->getDirection() != NEG_Y) { 561 | auto otherPos = targetPos + facingToBlockPos(POS_Y); 562 | for (auto facing = 2; facing <= 5; facing++) { 563 | checkBaseRailTransporterComponent(powerAssociationMap, info, stack, otherPos, static_cast(facing), 564 | false); 565 | } 566 | auto down = this->getComponent(otherPos, CSPB); 567 | for (auto facing = 2; facing <= 5; facing++) { 568 | checkBaseRailTransporterComponent(powerAssociationMap, info, stack, otherPos, static_cast(facing), 569 | false); 570 | } 571 | } else { 572 | auto topPos = targetPos + facingToBlockPos(POS_Y); 573 | auto downPos = targetPos + facingToBlockPos(NEG_Y); 574 | auto topComp = getComponent(topPos, CSPB); 575 | auto downComp = getComponent(downPos, CSPB); 576 | if (topComp) { //todo 577 | for (auto facing = 2; facing <= 5; facing++) { 578 | checkBaseRailTransporterComponent(powerAssociationMap, info, stack, 579 | const_cast(targetPos), 580 | static_cast(facing), 581 | false); 582 | } 583 | } 584 | } 585 | } 586 | 587 | 588 | //寻找前后左右四个方向的红石线加入队列 589 | void CircuitSceneGraph::checkTransporterComponent(CircuitComponentList &powerAssociationMap, 590 | CircuitTrackingInfo &info, 591 | std::queue &queue, 592 | BlockPos &pos, FACING dir, 593 | bool goingDown) { 594 | auto position = pos + facingToBlockPos(dir); 595 | auto component = this->getComponent(position, CSTR); 596 | addToFillQueue(this, powerAssociationMap, component, info, position, dir, queue); 597 | } 598 | 599 | void CircuitSceneGraph::checkBaseRailTransporterComponent(CircuitComponentList &powerAssociationMap, 600 | CircuitTrackingInfo &info, 601 | std::queue &queue, BlockPos &pos, 602 | FACING dir, bool goingDown) { 603 | auto position = pos + facingToBlockPos(dir); 604 | auto component = this->getComponent(position, MCPR); 605 | addToFillQueue(this, powerAssociationMap, component, info, position, dir, queue); 606 | } 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | --------------------------------------------------------------------------------