├── .gitignore ├── src └── main │ ├── php │ ├── GPBMetadata │ │ ├── Player.php │ │ ├── Xchange.php │ │ ├── AnticheatTypes.php │ │ ├── PlayerWrappers.php │ │ └── PrimitiveTypes.php │ └── prokits │ │ └── xyron │ │ ├── AnticheatInterface.php │ │ ├── ConsumeStatus.php │ │ ├── PlayerLifeData.php │ │ ├── Judgement.php │ │ ├── PlayerReceipt.php │ │ ├── BreakBlockStatus.php │ │ ├── PlayerEatFoodData.php │ │ ├── PlayerGameModeData.php │ │ ├── PlayerInputModeData.php │ │ ├── GameMode.php │ │ ├── InputMode.php │ │ ├── BatchedReportData.php │ │ ├── PlayerHeldItemChangeData.php │ │ ├── PlayerEffectData.php │ │ ├── TimestampedReportData.php │ │ ├── ReportResponse.php │ │ ├── BatchedReportResponse.php │ │ ├── Vec2i.php │ │ ├── Vec2f.php │ │ ├── Player.php │ │ ├── PlayerAttackData.php │ │ ├── AnticheatClient.php │ │ ├── PlayerMoveData.php │ │ ├── PlayerActionData.php │ │ ├── Vec3i.php │ │ ├── Vec3f.php │ │ ├── AxisAlignedBoundingBox.php │ │ ├── BatchedReportResponseEntry.php │ │ ├── BlockData.php │ │ ├── PlayerMotionData.php │ │ ├── AddPlayerRequest.php │ │ ├── JudgementData.php │ │ ├── PlayerBreakBlockData.php │ │ ├── PlayerPlaceBlockData.php │ │ ├── DeviceOS.php │ │ ├── ItemData.php │ │ ├── PlayerAction.php │ │ ├── ReportData.php │ │ ├── AttackData.php │ │ ├── DamageCause.php │ │ ├── EffectFeature.php │ │ ├── ItemFeature.php │ │ └── BlockFeature.php │ └── proto │ ├── anticheat_types.proto │ ├── xchange.proto │ ├── primitive_types.proto │ ├── player_wrappers.proto │ └── player.proto ├── pmmp_binding ├── plugin.yml ├── composer.json ├── src │ └── prokits │ │ └── xyron │ │ └── loader │ │ ├── XyronData.php │ │ └── BufferedDataQueue.php └── composer.lock ├── nukkit_binding ├── src │ └── main │ │ └── java │ │ └── com │ │ └── blackjack200 │ │ └── xyron │ │ └── nukkit │ │ ├── XyronData.java │ │ ├── BufferedDataQueue.java │ │ ├── BufferedDataFlushPool.java │ │ └── Main.java └── pom.xml ├── composer.json ├── implementation ├── util.go ├── jump_condition.go ├── default.go ├── speed_air.go ├── speed_ground.go └── gravity.go ├── main.go ├── pom.xml ├── LICENSE ├── Makefile ├── go.mod ├── java_protobuf ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── blackjack200 │ └── xyron │ └── AnticheatTypes.java ├── composer.lock ├── anticheat ├── violation_buffer.go ├── util.go ├── anticheat.go ├── player.go └── handlers.go ├── README.md └── xyron ├── anticheat_types.pb.go └── xchange_grpc.pb.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | players 4 | world 5 | config.toml 6 | resources 7 | target 8 | *.iml 9 | logs -------------------------------------------------------------------------------- /src/main/php/GPBMetadata/Player.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blackjack200/Xyron/HEAD/src/main/php/GPBMetadata/Player.php -------------------------------------------------------------------------------- /src/main/php/GPBMetadata/Xchange.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blackjack200/Xyron/HEAD/src/main/php/GPBMetadata/Xchange.php -------------------------------------------------------------------------------- /src/main/php/GPBMetadata/AnticheatTypes.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blackjack200/Xyron/HEAD/src/main/php/GPBMetadata/AnticheatTypes.php -------------------------------------------------------------------------------- /src/main/php/GPBMetadata/PlayerWrappers.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blackjack200/Xyron/HEAD/src/main/php/GPBMetadata/PlayerWrappers.php -------------------------------------------------------------------------------- /src/main/php/GPBMetadata/PrimitiveTypes.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blackjack200/Xyron/HEAD/src/main/php/GPBMetadata/PrimitiveTypes.php -------------------------------------------------------------------------------- /pmmp_binding/plugin.yml: -------------------------------------------------------------------------------- 1 | name: XyronLoader 2 | main: prokits\xyron\loader\Loader 3 | version: 0.1.0 4 | api: 5.0.0 5 | author: Blackjack200 6 | load: POSTWORLD 7 | depend: 8 | - libasync -------------------------------------------------------------------------------- /pmmp_binding/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blackjack200/xyron-loader", 3 | "type": "project", 4 | "require": { 5 | "blackjack200/xyron": "dev-master", 6 | "ext-grpc": "*", 7 | "ext-pmmpthread": "*" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /pmmp_binding/src/prokits/xyron/loader/XyronData.php: -------------------------------------------------------------------------------- 1 | queue; } 15 | } -------------------------------------------------------------------------------- /src/main/proto/anticheat_types.proto: -------------------------------------------------------------------------------- 1 | syntax = 'proto3'; 2 | 3 | option go_package = "xyron/"; 4 | option php_namespace = "prokits\\xyron"; 5 | option java_package = "com.github.blackjack200.xyron"; 6 | option java_generic_services = true; 7 | option php_generic_services = true; 8 | 9 | package xchange; 10 | 11 | enum Judgement { 12 | DEBUG = 0; 13 | AMBIGUOUS = 1; 14 | TRIGGER = 2; 15 | } 16 | -------------------------------------------------------------------------------- /nukkit_binding/src/main/java/com/blackjack200/xyron/nukkit/XyronData.java: -------------------------------------------------------------------------------- 1 | package com.blackjack200.xyron.nukkit; 2 | 3 | import com.github.blackjack200.xyron.Xchange; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | @AllArgsConstructor 8 | public class XyronData { 9 | @Getter 10 | private Xchange.PlayerReceipt receipt; 11 | @Getter 12 | private BufferedDataQueue queue; 13 | } 14 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blackjack200/xyron", 3 | "type": "library", 4 | "license": "MIT", 5 | "autoload": { 6 | "psr-4": { 7 | "": [ 8 | "src/main/php" 9 | ] 10 | } 11 | }, 12 | "authors": [ 13 | { 14 | "name": "Blackjack200", 15 | "email": "lx826444126@gmail.com" 16 | } 17 | ], 18 | "require": { 19 | "google/protobuf": "^3.23.4" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /implementation/util.go: -------------------------------------------------------------------------------- 1 | package implementation 2 | 3 | import ( 4 | "github.com/blackjack200/xyron/xyron" 5 | "github.com/df-mc/dragonfly/server/block/cube" 6 | "github.com/go-gl/mathgl/mgl64" 7 | "math" 8 | ) 9 | 10 | func toVec3(pos *xyron.Vec3F) mgl64.Vec3 { 11 | return mgl64.Vec3{ 12 | float64(pos.X), 13 | float64(pos.Y), 14 | float64(pos.Z), 15 | } 16 | } 17 | 18 | func ToRotation(vec3 mgl64.Vec3) cube.Rotation { 19 | pitchRad := math.Asin(-vec3.Y()) 20 | m := math.Cos(pitchRad) 21 | yawRad := math.Acos(vec3.Z() / m) 22 | return cube.Rotation{ 23 | mgl64.RadToDeg(yawRad), 24 | mgl64.RadToDeg(pitchRad), 25 | } 26 | } 27 | 28 | func isZero(y float64) bool { 29 | return math.Abs(mgl64.Clamp(y, -epsilon, epsilon)) > epsilon 30 | } 31 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/blackjack200/xyron/anticheat" 7 | "github.com/blackjack200/xyron/implementation" 8 | "github.com/blackjack200/xyron/xyron" 9 | "github.com/sirupsen/logrus" 10 | "google.golang.org/grpc" 11 | "log" 12 | "net" 13 | ) 14 | 15 | func main() { 16 | flag.Parse() 17 | lis, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", 8884)) 18 | if err != nil { 19 | log.Fatalf("failed to listen: %v", err) 20 | } 21 | log.Print("Listen") 22 | s := grpc.NewServer() 23 | t, stop := anticheat.NewSimpleAnticheatServer(logrus.New(), implementation.Available) 24 | xyron.RegisterAnticheatServer(s, t) 25 | if err := s.Serve(lis); err != nil { 26 | panic(err) 27 | } 28 | s.Stop() 29 | stop() 30 | } 31 | -------------------------------------------------------------------------------- /pmmp_binding/src/prokits/xyron/loader/BufferedDataQueue.php: -------------------------------------------------------------------------------- 1 | data[$tick])) { 15 | $this->data[$tick] = []; 16 | } 17 | $this->data[$tick][] = $data; 18 | } 19 | 20 | public function flush(int $tick, Closure &$remove) : Generator { 21 | $tks = []; 22 | foreach ($this->data as $tck => $data) { 23 | if ($tck <= $tick) { 24 | yield $tck => $data; 25 | $tks[] = $tck; 26 | } 27 | } 28 | $remove = function() use ($tks) : void { 29 | foreach ($tks as $tck) { 30 | unset($this->data[$tck]); 31 | } 32 | }; 33 | } 34 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.blackjack200 8 | xyron 9 | pom 10 | 0.0.1 11 | 12 | nukkit_binding 13 | java_protobuf 14 | 15 | 16 | 17 | 18 | 19 | org.projectlombok 20 | lombok 21 | 1.18.28 22 | provided 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 AZ1IDJC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PHP_BUILD_PLUGIN=`which grpc_php_plugin` 2 | GO_BUILD_PLUGIN=`which protoc-gen-go-grpc` 3 | JAVA_BUILD_PLUGIN=`which protoc-gen-grpc-java` 4 | 5 | PHP_PROTO_OUT="src/main/php" 6 | 7 | GO_PROTO_BASEDIR="./" 8 | GO_PROTO_OUT="xyron" 9 | 10 | JAVA_PROTO_OUT="java_protobuf/src/main/java" 11 | 12 | php: 13 | @mkdir -p $(PHP_PROTO_OUT) 14 | @rm -rdf $(PHP_PROTO_OUT) 15 | @mkdir -p $(PHP_PROTO_OUT) 16 | @cd src/main/proto && protoc --plugin=protoc-gen-grpc=$(PHP_BUILD_PLUGIN) ./*.proto --php_out="../../../$(PHP_PROTO_OUT)" --grpc_out="../../../$(PHP_PROTO_OUT)" 17 | 18 | go: 19 | @rm -rdf $(GO_PROTO_OUT) 20 | @mkdir -p $(GO_PROTO_OUT) 21 | @cd src/main/proto && protoc --plugin=protoc-gen-grpc=$(GO_BUILD_PLUGIN) ./*.proto --go_out="../../../$(GO_PROTO_BASEDIR)" --grpc_out="../../../$(GO_PROTO_BASEDIR)" 22 | 23 | java: 24 | @mkdir -p $(JAVA_PROTO_OUT) 25 | @rm -rdf $(JAVA_PROTO_OUT) 26 | @mkdir -p $(JAVA_PROTO_OUT) 27 | @cd src/main/proto && protoc --plugin=protoc-gen-grpc=$(JAVA_BUILD_PLUGIN) ./*.proto --java_out="../../../$(JAVA_PROTO_OUT)" --grpc_out="../../../$(JAVA_PROTO_OUT)" 28 | 29 | all: 30 | @make php 31 | @make go 32 | @make java -------------------------------------------------------------------------------- /implementation/jump_condition.go: -------------------------------------------------------------------------------- 1 | package implementation 2 | 3 | import ( 4 | "fmt" 5 | "github.com/blackjack200/xyron/anticheat" 6 | "github.com/blackjack200/xyron/xyron" 7 | ) 8 | 9 | type JumpCondition struct { 10 | *anticheat.Evaluator 11 | UnstableRate float64 12 | } 13 | 14 | var _ = anticheat.ActionDataHandler(&JumpCondition{}) 15 | 16 | func init() { 17 | register(func() any { 18 | return &JumpCondition{ 19 | anticheat.NewEvaluator(8, 0.3, 0.8), 20 | 0.9999, 21 | } 22 | }) 23 | } 24 | 25 | func (a *JumpCondition) HandleActionData(p *anticheat.InternalPlayer, data *xyron.PlayerActionData) *xyron.JudgementData { 26 | measured := 0.0 27 | newOnGround, _, _, _, _, _, _ := p.CheckGroundState(data.Position) 28 | if data.Action == xyron.PlayerAction_Jump && 29 | !p.OnGround.Current().Get() && 30 | !newOnGround && 31 | p.InAirTick >= 15 { 32 | measured = 1 33 | } 34 | if !p.Location.Current().AllowFlying && !data.Position.AllowFlying { 35 | a.HandleUnstableRate(measured, 0, a.UnstableRate) 36 | } 37 | return &xyron.JudgementData{ 38 | Type: "JumpCondition", 39 | Judgement: a.Evaluate(), 40 | Message: fmt.Sprintf("p:%v inAirTick:%v", a.PossibilityString(), p.InAirTick), 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/AnticheatInterface.php: -------------------------------------------------------------------------------- 1 | xchange.Anticheat 9 | */ 10 | interface AnticheatInterface 11 | { 12 | /** 13 | * Method addPlayer 14 | * 15 | * @param \prokits\xyron\AddPlayerRequest $request 16 | * @return \prokits\xyron\PlayerReceipt 17 | */ 18 | public function addPlayer(\prokits\xyron\AddPlayerRequest $request); 19 | 20 | /** 21 | * Method removePlayer 22 | * 23 | * @param \prokits\xyron\PlayerReceipt $request 24 | * @return \Google\Protobuf\GPBEmpty 25 | */ 26 | public function removePlayer(\prokits\xyron\PlayerReceipt $request); 27 | 28 | /** 29 | * Method report 30 | * 31 | * @param \prokits\xyron\ReportData $request 32 | * @return \prokits\xyron\ReportResponse 33 | */ 34 | public function report(\prokits\xyron\ReportData $request); 35 | 36 | /** 37 | * Method reportBatched 38 | * 39 | * @param \prokits\xyron\BatchedReportData $request 40 | * @return \prokits\xyron\BatchedReportResponse 41 | */ 42 | public function reportBatched(\prokits\xyron\BatchedReportData $request); 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/ConsumeStatus.php: -------------------------------------------------------------------------------- 1 | xchange.ConsumeStatus 11 | */ 12 | class ConsumeStatus 13 | { 14 | /** 15 | * Generated from protobuf enum Start = 0; 16 | */ 17 | const Start = 0; 18 | /** 19 | * Generated from protobuf enum Stop = 1; 20 | */ 21 | const Stop = 1; 22 | 23 | private static $valueToName = [ 24 | self::Start => 'Start', 25 | self::Stop => 'Stop', 26 | ]; 27 | 28 | public static function name($value) 29 | { 30 | if (!isset(self::$valueToName[$value])) { 31 | throw new UnexpectedValueException(sprintf( 32 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 33 | } 34 | return self::$valueToName[$value]; 35 | } 36 | 37 | 38 | public static function value($name) 39 | { 40 | $const = __CLASS__ . '::' . strtoupper($name); 41 | if (!defined($const)) { 42 | throw new UnexpectedValueException(sprintf( 43 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 44 | } 45 | return constant($const); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerLifeData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerLifeData 13 | */ 14 | class PlayerLifeData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field bool alive = 1; 18 | */ 19 | protected $alive = false; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type bool $alive 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\PlayerWrappers::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field bool alive = 1; 37 | * @return bool 38 | */ 39 | public function getAlive() 40 | { 41 | return $this->alive; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field bool alive = 1; 46 | * @param bool $var 47 | * @return $this 48 | */ 49 | public function setAlive($var) 50 | { 51 | GPBUtil::checkBool($var); 52 | $this->alive = $var; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/Judgement.php: -------------------------------------------------------------------------------- 1 | xchange.Judgement 11 | */ 12 | class Judgement 13 | { 14 | /** 15 | * Generated from protobuf enum DEBUG = 0; 16 | */ 17 | const DEBUG = 0; 18 | /** 19 | * Generated from protobuf enum AMBIGUOUS = 1; 20 | */ 21 | const AMBIGUOUS = 1; 22 | /** 23 | * Generated from protobuf enum TRIGGER = 2; 24 | */ 25 | const TRIGGER = 2; 26 | 27 | private static $valueToName = [ 28 | self::DEBUG => 'DEBUG', 29 | self::AMBIGUOUS => 'AMBIGUOUS', 30 | self::TRIGGER => 'TRIGGER', 31 | ]; 32 | 33 | public static function name($value) 34 | { 35 | if (!isset(self::$valueToName[$value])) { 36 | throw new UnexpectedValueException(sprintf( 37 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 38 | } 39 | return self::$valueToName[$value]; 40 | } 41 | 42 | 43 | public static function value($name) 44 | { 45 | $const = __CLASS__ . '::' . strtoupper($name); 46 | if (!defined($const)) { 47 | throw new UnexpectedValueException(sprintf( 48 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 49 | } 50 | return constant($const); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerReceipt.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerReceipt 13 | */ 14 | class PlayerReceipt extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field string internalId = 1; 18 | */ 19 | protected $internalId = ''; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type string $internalId 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\Xchange::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field string internalId = 1; 37 | * @return string 38 | */ 39 | public function getInternalId() 40 | { 41 | return $this->internalId; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field string internalId = 1; 46 | * @param string $var 47 | * @return $this 48 | */ 49 | public function setInternalId($var) 50 | { 51 | GPBUtil::checkString($var, True); 52 | $this->internalId = $var; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/BreakBlockStatus.php: -------------------------------------------------------------------------------- 1 | xchange.BreakBlockStatus 11 | */ 12 | class BreakBlockStatus 13 | { 14 | /** 15 | * Generated from protobuf enum StartBreak = 0; 16 | */ 17 | const StartBreak = 0; 18 | /** 19 | * Generated from protobuf enum AbortBreak = 1; 20 | */ 21 | const AbortBreak = 1; 22 | /** 23 | * Generated from protobuf enum FinishBreak = 2; 24 | */ 25 | const FinishBreak = 2; 26 | 27 | private static $valueToName = [ 28 | self::StartBreak => 'StartBreak', 29 | self::AbortBreak => 'AbortBreak', 30 | self::FinishBreak => 'FinishBreak', 31 | ]; 32 | 33 | public static function name($value) 34 | { 35 | if (!isset(self::$valueToName[$value])) { 36 | throw new UnexpectedValueException(sprintf( 37 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 38 | } 39 | return self::$valueToName[$value]; 40 | } 41 | 42 | 43 | public static function value($name) 44 | { 45 | $const = __CLASS__ . '::' . strtoupper($name); 46 | if (!defined($const)) { 47 | throw new UnexpectedValueException(sprintf( 48 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 49 | } 50 | return constant($const); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /implementation/default.go: -------------------------------------------------------------------------------- 1 | package implementation 2 | 3 | import ( 4 | "github.com/blackjack200/xyron/anticheat" 5 | "github.com/blackjack200/xyron/xyron" 6 | ) 7 | 8 | var Available = func() []any { 9 | return nil 10 | } 11 | 12 | const epsilon = 0.00001 13 | 14 | func register(newF func() any) { 15 | oldA := Available 16 | Available = func() []any { 17 | return append(oldA(), newF()) 18 | } 19 | } 20 | 21 | func clear() { 22 | Available = func() []any { 23 | return nil 24 | } 25 | } 26 | 27 | func isPlayerFreeFalling(p *anticheat.InternalPlayer, futurePos *xyron.EntityPositionData) bool { 28 | if p.Location.Previous() == nil { 29 | return true 30 | } 31 | y := p.Motion.Current().Get().Y() 32 | 33 | tickSinceTeleport := p.Teleport.Current().Duration(p.CurrentTimestamp()) 34 | tickSinceFlying := p.Flying.Current().Duration(p.CurrentTimestamp()) 35 | tickSinceMotion := p.Motion.Current().Duration(p.CurrentTimestamp()) 36 | tickSinceJump := p.Jump.Current().Duration(p.CurrentTimestamp()) 37 | 38 | // we shouldn't use "future" data, but this is a special condition, false positives appear when player land and death. 39 | futureOnGround, _, _, _, _, _, _ := p.CheckGroundState(futurePos) 40 | futureImmobile := futurePos.IsImmobile 41 | 42 | if !isZero(y) && 43 | !p.Location.Current().IsImmobile && !futureImmobile && 44 | futurePos.Position.Y > -64 && 45 | tickSinceTeleport > 40 && tickSinceFlying > 10 && tickSinceJump > 15 && 46 | tickSinceMotion > p.MotionCoolDown && 47 | p.InAirTick > 15 && !futureOnGround && 48 | !p.IntersectedLiquid.Current().Get() { 49 | return true 50 | } 51 | return false 52 | } 53 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerEatFoodData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerEatFoodData 13 | */ 14 | class PlayerEatFoodData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.ConsumeStatus status = 2; 18 | */ 19 | protected $status = 0; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type int $status 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\PlayerWrappers::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field .xchange.ConsumeStatus status = 2; 37 | * @return int 38 | */ 39 | public function getStatus() 40 | { 41 | return $this->status; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field .xchange.ConsumeStatus status = 2; 46 | * @param int $var 47 | * @return $this 48 | */ 49 | public function setStatus($var) 50 | { 51 | GPBUtil::checkEnum($var, \prokits\xyron\ConsumeStatus::class); 52 | $this->status = $var; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerGameModeData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerGameModeData 13 | */ 14 | class PlayerGameModeData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.GameMode gameMode = 1; 18 | */ 19 | protected $gameMode = 0; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type int $gameMode 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\PlayerWrappers::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field .xchange.GameMode gameMode = 1; 37 | * @return int 38 | */ 39 | public function getGameMode() 40 | { 41 | return $this->gameMode; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field .xchange.GameMode gameMode = 1; 46 | * @param int $var 47 | * @return $this 48 | */ 49 | public function setGameMode($var) 50 | { 51 | GPBUtil::checkEnum($var, \prokits\xyron\GameMode::class); 52 | $this->gameMode = $var; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/blackjack200/xyron 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/df-mc/dragonfly v0.9.9-0.20230714144543-281943e6efc4 7 | github.com/go-gl/mathgl v1.0.0 8 | github.com/pelletier/go-toml v1.9.5 9 | github.com/sirupsen/logrus v1.9.3 10 | google.golang.org/grpc v1.56.2 11 | google.golang.org/protobuf v1.31.0 12 | ) 13 | 14 | require ( 15 | github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9 // indirect 16 | github.com/cespare/xxhash v1.1.0 // indirect 17 | github.com/df-mc/atomic v1.10.0 // indirect 18 | github.com/df-mc/goleveldb v1.1.9 // indirect 19 | github.com/df-mc/worldupgrader v1.0.8 // indirect 20 | github.com/golang/protobuf v1.5.3 // indirect 21 | github.com/golang/snappy v0.0.4 // indirect 22 | github.com/google/uuid v1.3.0 // indirect 23 | github.com/klauspost/compress v1.16.7 // indirect 24 | github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect 25 | github.com/rogpeppe/go-internal v1.11.0 // indirect 26 | github.com/sandertv/go-raknet v1.12.0 // indirect 27 | github.com/sandertv/gophertunnel v1.31.0 // indirect 28 | go.uber.org/atomic v1.11.0 // indirect 29 | golang.org/x/crypto v0.11.0 // indirect 30 | golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect 31 | golang.org/x/image v0.9.0 // indirect 32 | golang.org/x/net v0.12.0 // indirect 33 | golang.org/x/oauth2 v0.10.0 // indirect 34 | golang.org/x/sys v0.10.0 // indirect 35 | golang.org/x/text v0.11.0 // indirect 36 | google.golang.org/appengine v1.6.7 // indirect 37 | google.golang.org/genproto/googleapis/rpc v0.0.0-20230720185612-659f7aaaa771 // indirect 38 | gopkg.in/square/go-jose.v2 v2.6.0 // indirect 39 | ) 40 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerInputModeData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerInputModeData 13 | */ 14 | class PlayerInputModeData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.InputMode inputMode = 1; 18 | */ 19 | protected $inputMode = 0; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type int $inputMode 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\PlayerWrappers::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field .xchange.InputMode inputMode = 1; 37 | * @return int 38 | */ 39 | public function getInputMode() 40 | { 41 | return $this->inputMode; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field .xchange.InputMode inputMode = 1; 46 | * @param int $var 47 | * @return $this 48 | */ 49 | public function setInputMode($var) 50 | { 51 | GPBUtil::checkEnum($var, \prokits\xyron\InputMode::class); 52 | $this->inputMode = $var; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/GameMode.php: -------------------------------------------------------------------------------- 1 | xchange.GameMode 11 | */ 12 | class GameMode 13 | { 14 | /** 15 | * Generated from protobuf enum Survival = 0; 16 | */ 17 | const Survival = 0; 18 | /** 19 | * Generated from protobuf enum Creative = 1; 20 | */ 21 | const Creative = 1; 22 | /** 23 | * Generated from protobuf enum Adventure = 2; 24 | */ 25 | const Adventure = 2; 26 | /** 27 | * Generated from protobuf enum Spectator = 3; 28 | */ 29 | const Spectator = 3; 30 | 31 | private static $valueToName = [ 32 | self::Survival => 'Survival', 33 | self::Creative => 'Creative', 34 | self::Adventure => 'Adventure', 35 | self::Spectator => 'Spectator', 36 | ]; 37 | 38 | public static function name($value) 39 | { 40 | if (!isset(self::$valueToName[$value])) { 41 | throw new UnexpectedValueException(sprintf( 42 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 43 | } 44 | return self::$valueToName[$value]; 45 | } 46 | 47 | 48 | public static function value($name) 49 | { 50 | $const = __CLASS__ . '::' . strtoupper($name); 51 | if (!defined($const)) { 52 | throw new UnexpectedValueException(sprintf( 53 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 54 | } 55 | return constant($const); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/proto/xchange.proto: -------------------------------------------------------------------------------- 1 | syntax = 'proto3'; 2 | 3 | option go_package = "xyron/"; 4 | option php_namespace = "prokits\\xyron"; 5 | option java_package = "com.github.blackjack200.xyron"; 6 | option java_generic_services = true; 7 | option php_generic_services = true; 8 | 9 | package xchange; 10 | 11 | import "google/protobuf/empty.proto"; 12 | import "player_wrappers.proto"; 13 | import "player.proto"; 14 | import "anticheat_types.proto"; 15 | 16 | message PlayerReceipt { 17 | string internalId = 1; 18 | } 19 | 20 | message TimestampedReportData { 21 | repeated WildcardReportData data = 1; 22 | } 23 | 24 | message AddPlayerRequest{ 25 | Player player = 1; 26 | //timestamp->report data 27 | map data = 2; 28 | } 29 | 30 | message ReportData{ 31 | PlayerReceipt player = 1; 32 | double latency = 2; 33 | //timestamp->report data 34 | map data = 3; 35 | } 36 | 37 | message ReportResponse{ 38 | repeated JudgementData judgements = 1; 39 | } 40 | 41 | message BatchedReportData{ 42 | repeated ReportData data = 1; 43 | } 44 | 45 | message BatchedReportResponseEntry{ 46 | PlayerReceipt player = 1; 47 | repeated JudgementData judgements = 2; 48 | } 49 | 50 | message BatchedReportResponse{ 51 | repeated BatchedReportResponseEntry data = 1; 52 | } 53 | 54 | message JudgementData{ 55 | string type = 1; 56 | Judgement judgement = 2; 57 | string message = 3; 58 | } 59 | 60 | service Anticheat { 61 | rpc AddPlayer(AddPlayerRequest) returns (PlayerReceipt) {} 62 | rpc RemovePlayer(PlayerReceipt) returns (google.protobuf.Empty) {} 63 | rpc Report(ReportData) returns (ReportResponse){} 64 | rpc ReportBatched(BatchedReportData) returns (BatchedReportResponse){} 65 | } 66 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/InputMode.php: -------------------------------------------------------------------------------- 1 | xchange.InputMode 11 | */ 12 | class InputMode 13 | { 14 | /** 15 | * Generated from protobuf enum MouseKeyboard = 0; 16 | */ 17 | const MouseKeyboard = 0; 18 | /** 19 | * Generated from protobuf enum Touch = 1; 20 | */ 21 | const Touch = 1; 22 | /** 23 | * Generated from protobuf enum Gamepad = 2; 24 | */ 25 | const Gamepad = 2; 26 | /** 27 | * Generated from protobuf enum MotionController = 3; 28 | */ 29 | const MotionController = 3; 30 | 31 | private static $valueToName = [ 32 | self::MouseKeyboard => 'MouseKeyboard', 33 | self::Touch => 'Touch', 34 | self::Gamepad => 'Gamepad', 35 | self::MotionController => 'MotionController', 36 | ]; 37 | 38 | public static function name($value) 39 | { 40 | if (!isset(self::$valueToName[$value])) { 41 | throw new UnexpectedValueException(sprintf( 42 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 43 | } 44 | return self::$valueToName[$value]; 45 | } 46 | 47 | 48 | public static function value($name) 49 | { 50 | $const = __CLASS__ . '::' . strtoupper($name); 51 | if (!defined($const)) { 52 | throw new UnexpectedValueException(sprintf( 53 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 54 | } 55 | return constant($const); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/proto/primitive_types.proto: -------------------------------------------------------------------------------- 1 | syntax = 'proto3'; 2 | 3 | option go_package = "xyron/"; 4 | option php_namespace = "prokits\\xyron"; 5 | option java_package = "com.github.blackjack200.xyron"; 6 | option java_generic_services = true; 7 | option php_generic_services = true; 8 | 9 | package xchange; 10 | 11 | message Vec2f { 12 | float x = 1; 13 | float y = 2; 14 | } 15 | 16 | message Vec2i { 17 | int32 x = 1; 18 | int32 y = 2; 19 | } 20 | 21 | message Vec3f { 22 | float x = 1; 23 | float y = 2; 24 | float z = 3; 25 | } 26 | 27 | message Vec3i { 28 | int32 x = 1; 29 | int32 y = 2; 30 | int32 z = 3; 31 | } 32 | 33 | message AxisAlignedBoundingBox{ 34 | Vec3f min = 1; 35 | Vec3f max = 2; 36 | } 37 | 38 | message BlockData { 39 | BlockFeature feature = 1; 40 | Vec3i position = 2; 41 | } 42 | 43 | message BlockFeature { 44 | repeated AxisAlignedBoundingBox collisionBoxes = 2; 45 | float friction = 3; 46 | bool isSolid = 4; 47 | bool isLiquid = 5; 48 | bool isAir = 6; 49 | bool isSlime = 7; 50 | bool isClimbable = 8; 51 | bool isIce = 9; 52 | bool isCobweb = 10; 53 | bool isSweetBerry = 11; 54 | } 55 | 56 | message ItemData { 57 | ItemFeature feature = 1; 58 | string vanillaName = 2; 59 | uint32 count = 3; 60 | } 61 | 62 | message ItemFeature { 63 | bool isArmor = 1; 64 | bool isBlockPlanterItem = 2; 65 | bool isDamageable = 3; 66 | bool isFood = 4; 67 | bool isThrowable = 5; 68 | bool isTool = 6; 69 | bool isBow = 7; 70 | bool isCrossBow = 8; 71 | bool isShield = 9; 72 | } 73 | 74 | message EffectFeature { 75 | int32 amplifier = 1; 76 | bool isSpeed = 2; 77 | bool isHaste = 3; 78 | bool isSlowFalling = 4; 79 | bool isLevitation = 5; 80 | bool isSlowness = 6; 81 | bool isJumpBoost = 7; 82 | } -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/BatchedReportData.php: -------------------------------------------------------------------------------- 1 | xchange.BatchedReportData 13 | */ 14 | class BatchedReportData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field repeated .xchange.ReportData data = 1; 18 | */ 19 | private $data; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type array<\prokits\xyron\ReportData>|\Google\Protobuf\Internal\RepeatedField $data 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\Xchange::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field repeated .xchange.ReportData data = 1; 37 | * @return \Google\Protobuf\Internal\RepeatedField 38 | */ 39 | public function getData() 40 | { 41 | return $this->data; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field repeated .xchange.ReportData data = 1; 46 | * @param array<\prokits\xyron\ReportData>|\Google\Protobuf\Internal\RepeatedField $var 47 | * @return $this 48 | */ 49 | public function setData($var) 50 | { 51 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\ReportData::class); 52 | $this->data = $arr; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /nukkit_binding/src/main/java/com/blackjack200/xyron/nukkit/BufferedDataQueue.java: -------------------------------------------------------------------------------- 1 | package com.blackjack200.xyron.nukkit; 2 | 3 | import com.github.blackjack200.xyron.AnticheatGrpc; 4 | import com.github.blackjack200.xyron.PlayerWrappers; 5 | import com.github.blackjack200.xyron.Xchange; 6 | import com.google.common.util.concurrent.ListenableFuture; 7 | import lombok.val; 8 | 9 | import java.util.LinkedHashMap; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | public class BufferedDataQueue { 15 | private final Map> map = new LinkedHashMap<>(80); 16 | 17 | public synchronized void add(long tick, PlayerWrappers.WildcardReportData wdata) { 18 | if (!map.containsKey(tick)) { 19 | map.put(tick, new LinkedList<>()); 20 | } 21 | map.get(tick).add(wdata); 22 | } 23 | 24 | public synchronized ListenableFuture flush(AnticheatGrpc.AnticheatFutureStub c, Xchange.PlayerReceipt p, long tick, double latency) { 25 | val needSend = new LinkedList(); 26 | for (val k : map.keySet()) { 27 | if (k <= tick) { 28 | needSend.add(k); 29 | } 30 | } 31 | needSend.sort(Long::compare); 32 | val needSendMap = new LinkedHashMap(); 33 | for (val timestamp : needSend) { 34 | needSendMap.put(timestamp, Xchange.TimestampedReportData.newBuilder() 35 | .addAllData(map.get(timestamp)).build()); 36 | map.remove(timestamp); 37 | } 38 | val rp = Xchange.ReportData.newBuilder() 39 | .setPlayer(p) 40 | .setLatency(latency) 41 | .putAllData(needSendMap) 42 | .build(); 43 | return c.report(rp); 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerHeldItemChangeData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerHeldItemChangeData 13 | */ 14 | class PlayerHeldItemChangeData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.ItemData item = 1; 18 | */ 19 | protected $item = null; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type \prokits\xyron\ItemData $item 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\PlayerWrappers::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field .xchange.ItemData item = 1; 37 | * @return \prokits\xyron\ItemData|null 38 | */ 39 | public function getItem() 40 | { 41 | return $this->item; 42 | } 43 | 44 | public function hasItem() 45 | { 46 | return isset($this->item); 47 | } 48 | 49 | public function clearItem() 50 | { 51 | unset($this->item); 52 | } 53 | 54 | /** 55 | * Generated from protobuf field .xchange.ItemData item = 1; 56 | * @param \prokits\xyron\ItemData $var 57 | * @return $this 58 | */ 59 | public function setItem($var) 60 | { 61 | GPBUtil::checkMessage($var, \prokits\xyron\ItemData::class); 62 | $this->item = $var; 63 | 64 | return $this; 65 | } 66 | 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerEffectData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerEffectData 13 | */ 14 | class PlayerEffectData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field repeated .xchange.EffectFeature effect = 1; 18 | */ 19 | private $effect; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type array<\prokits\xyron\EffectFeature>|\Google\Protobuf\Internal\RepeatedField $effect 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\PlayerWrappers::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field repeated .xchange.EffectFeature effect = 1; 37 | * @return \Google\Protobuf\Internal\RepeatedField 38 | */ 39 | public function getEffect() 40 | { 41 | return $this->effect; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field repeated .xchange.EffectFeature effect = 1; 46 | * @param array<\prokits\xyron\EffectFeature>|\Google\Protobuf\Internal\RepeatedField $var 47 | * @return $this 48 | */ 49 | public function setEffect($var) 50 | { 51 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\EffectFeature::class); 52 | $this->effect = $arr; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/TimestampedReportData.php: -------------------------------------------------------------------------------- 1 | xchange.TimestampedReportData 13 | */ 14 | class TimestampedReportData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field repeated .xchange.WildcardReportData data = 1; 18 | */ 19 | private $data; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type array<\prokits\xyron\WildcardReportData>|\Google\Protobuf\Internal\RepeatedField $data 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\Xchange::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field repeated .xchange.WildcardReportData data = 1; 37 | * @return \Google\Protobuf\Internal\RepeatedField 38 | */ 39 | public function getData() 40 | { 41 | return $this->data; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field repeated .xchange.WildcardReportData data = 1; 46 | * @param array<\prokits\xyron\WildcardReportData>|\Google\Protobuf\Internal\RepeatedField $var 47 | * @return $this 48 | */ 49 | public function setData($var) 50 | { 51 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\WildcardReportData::class); 52 | $this->data = $arr; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/ReportResponse.php: -------------------------------------------------------------------------------- 1 | xchange.ReportResponse 13 | */ 14 | class ReportResponse extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field repeated .xchange.JudgementData judgements = 1; 18 | */ 19 | private $judgements; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type array<\prokits\xyron\JudgementData>|\Google\Protobuf\Internal\RepeatedField $judgements 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\Xchange::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field repeated .xchange.JudgementData judgements = 1; 37 | * @return \Google\Protobuf\Internal\RepeatedField 38 | */ 39 | public function getJudgements() 40 | { 41 | return $this->judgements; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field repeated .xchange.JudgementData judgements = 1; 46 | * @param array<\prokits\xyron\JudgementData>|\Google\Protobuf\Internal\RepeatedField $var 47 | * @return $this 48 | */ 49 | public function setJudgements($var) 50 | { 51 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\JudgementData::class); 52 | $this->judgements = $arr; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /implementation/speed_air.go: -------------------------------------------------------------------------------- 1 | package implementation 2 | 3 | import ( 4 | "fmt" 5 | "github.com/blackjack200/xyron/anticheat" 6 | "github.com/blackjack200/xyron/xyron" 7 | "math" 8 | ) 9 | 10 | type SpeedAir struct { 11 | *anticheat.Evaluator 12 | PredictionLatitude float64 13 | UnstableRate float64 14 | } 15 | 16 | var _ anticheat.MoveDataHandler = &SpeedAir{} 17 | 18 | func init() { 19 | register(func() any { 20 | return &SpeedAir{ 21 | anticheat.NewEvaluator(80, 0.75, 0.96), 22 | 0.05, 23 | 0.997, 24 | } 25 | }) 26 | } 27 | 28 | func (g *SpeedAir) HandleMoveData(p *anticheat.InternalPlayer, data *xyron.PlayerMoveData) *xyron.JudgementData { 29 | if !isPlayerFreeFalling(p, data.NewPosition) { 30 | return nil 31 | } 32 | if p.Location.Previous() == nil { 33 | return nil 34 | } 35 | oldPos := toVec3(p.Location.Previous().Position) 36 | pos := toVec3(p.Location.Current().Position) 37 | delta := pos.Sub(oldPos) 38 | 39 | futurePos := toVec3(data.NewPosition.Position) 40 | deltaFuture := futurePos.Sub(oldPos) 41 | 42 | deltaXZ := math.Hypot(delta.X(), delta.Z()) 43 | measuredFutureDeltaXZ := math.Hypot(deltaFuture.X(), deltaFuture.Z()) 44 | if isZero(futurePos.Sub(pos).Len()) { 45 | return nil 46 | } 47 | 48 | factor := 0.02 49 | if p.Sprinting.Current().Get() { 50 | factor = 0.026 51 | } 52 | predictedMaxDeltaXZ := deltaXZ*0.91 + factor 53 | 54 | if !p.Location.Current().IsFlying && 55 | !data.NewPosition.IsFlying && 56 | !p.Location.Current().AllowFlying { 57 | g.HandleRelativeUnstableRate(measuredFutureDeltaXZ, predictedMaxDeltaXZ, g.PredictionLatitude, g.UnstableRate) 58 | } 59 | 60 | equalness := math.Abs(measuredFutureDeltaXZ - predictedMaxDeltaXZ) 61 | return &xyron.JudgementData{ 62 | Type: "SpeedAir", 63 | Judgement: g.Evaluate(), 64 | Message: fmt.Sprintf("p:%v pred-xz:%.5f xz:%.5f delta:%.5f", g.PossibilityString(), predictedMaxDeltaXZ, deltaXZ, equalness), 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/BatchedReportResponse.php: -------------------------------------------------------------------------------- 1 | xchange.BatchedReportResponse 13 | */ 14 | class BatchedReportResponse extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field repeated .xchange.BatchedReportResponseEntry data = 1; 18 | */ 19 | private $data; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param array $data { 25 | * Optional. Data for populating the Message object. 26 | * 27 | * @type array<\prokits\xyron\BatchedReportResponseEntry>|\Google\Protobuf\Internal\RepeatedField $data 28 | * } 29 | */ 30 | public function __construct($data = NULL) { 31 | \GPBMetadata\Xchange::initOnce(); 32 | parent::__construct($data); 33 | } 34 | 35 | /** 36 | * Generated from protobuf field repeated .xchange.BatchedReportResponseEntry data = 1; 37 | * @return \Google\Protobuf\Internal\RepeatedField 38 | */ 39 | public function getData() 40 | { 41 | return $this->data; 42 | } 43 | 44 | /** 45 | * Generated from protobuf field repeated .xchange.BatchedReportResponseEntry data = 1; 46 | * @param array<\prokits\xyron\BatchedReportResponseEntry>|\Google\Protobuf\Internal\RepeatedField $var 47 | * @return $this 48 | */ 49 | public function setData($var) 50 | { 51 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\BatchedReportResponseEntry::class); 52 | $this->data = $arr; 53 | 54 | return $this; 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /nukkit_binding/src/main/java/com/blackjack200/xyron/nukkit/BufferedDataFlushPool.java: -------------------------------------------------------------------------------- 1 | package com.blackjack200.xyron.nukkit; 2 | 3 | import cn.nukkit.Server; 4 | import com.google.common.util.concurrent.ListenableFuture; 5 | import lombok.SneakyThrows; 6 | import lombok.val; 7 | import lombok.var; 8 | 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.concurrent.Future; 14 | import java.util.function.Consumer; 15 | 16 | public class BufferedDataFlushPool { 17 | private final List> futures = new ArrayList<>(); 18 | private final Map, Consumer> callbackMap = new HashMap<>(); 19 | 20 | @SuppressWarnings("unchecked") 21 | public synchronized void add(ListenableFuture future, Consumer callback) { 22 | futures.add((Future) future); 23 | callbackMap.put((Future) future, (Consumer) callback); 24 | } 25 | 26 | public void poll() { 27 | val completedFutures = new HashMap, Consumer>(); 28 | synchronized (this) { 29 | for (val future : futures) { 30 | if (future.isDone()) { 31 | completedFutures.put(future, callbackMap.get(future)); 32 | callbackMap.remove(future); 33 | } 34 | } 35 | futures.removeAll(completedFutures.keySet()); 36 | } 37 | completedFutures.forEach((future, consumer) -> { 38 | try { 39 | consumer.accept(future.get()); 40 | } catch (Throwable e) { 41 | Server.getInstance().getLogger().logException(e); 42 | } 43 | }); 44 | } 45 | 46 | @SneakyThrows 47 | public synchronized void shutdown() { 48 | var counter = 1 << 30; 49 | while (this.futures.size() > 0 && counter-- > 0) { 50 | this.poll(); 51 | Thread.sleep(100); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /nukkit_binding/src/main/java/com/blackjack200/xyron/nukkit/Main.java: -------------------------------------------------------------------------------- 1 | package com.blackjack200.xyron.nukkit; 2 | 3 | import com.github.blackjack200.xyron.AnticheatGrpc; 4 | import com.github.blackjack200.xyron.PlayerOuterClass; 5 | import com.github.blackjack200.xyron.PlayerWrappers; 6 | import com.github.blackjack200.xyron.Xchange; 7 | import io.grpc.ManagedChannelBuilder; 8 | import lombok.val; 9 | 10 | import java.util.concurrent.ExecutionException; 11 | 12 | public class Main { 13 | public static void main(String[] args) throws ExecutionException, InterruptedException { 14 | val channel = ManagedChannelBuilder.forAddress("localhost", 8884).usePlaintext().build(); 15 | val client = AnticheatGrpc.newFutureStub(channel).withWaitForReady(); 16 | val req = Xchange.AddPlayerRequest.newBuilder() 17 | .setPlayer(PlayerOuterClass.Player.newBuilder() 18 | .setOsValue(PlayerOuterClass.DeviceOS.Android_VALUE) 19 | .setName("IPlayfordev") 20 | ); 21 | req.putData(0L, Xchange.TimestampedReportData.newBuilder() 22 | .addData(PlayerWrappers.WildcardReportData.newBuilder().setGameModeData( 23 | PlayerWrappers.PlayerGameModeData.newBuilder() 24 | .setGameModeValue(PlayerOuterClass.GameMode.Survival_VALUE) 25 | )).build() 26 | ); 27 | val ppf = client.addPlayer(req.build()); 28 | while(!ppf.isDone()){ 29 | System.out.println("W"); 30 | } 31 | val pp = ppf.get(); 32 | System.out.println(pp.getInternalId()); 33 | val rp = Xchange.ReportData.newBuilder() 34 | .setPlayer(pp) 35 | .setLatency(0.01); 36 | val jd = client.report(rp.build()).get(); 37 | for (val j : jd.getJudgementsList()) { 38 | System.out.println(j.getJudgement()); 39 | } 40 | client.removePlayer(pp).get(); 41 | channel.shutdownNow(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/proto/player_wrappers.proto: -------------------------------------------------------------------------------- 1 | syntax = 'proto3'; 2 | 3 | option go_package = "xyron/"; 4 | option php_namespace = "prokits\\xyron"; 5 | option java_package = "com.github.blackjack200.xyron"; 6 | option java_generic_services = true; 7 | option php_generic_services = true; 8 | 9 | package xchange; 10 | 11 | import "player.proto"; 12 | import "primitive_types.proto"; 13 | 14 | message WildcardReportData { 15 | oneof data{ 16 | PlayerActionData action_data = 1; 17 | PlayerMoveData move_data = 2; 18 | PlayerPlaceBlockData place_block_data = 3; 19 | PlayerBreakBlockData break_block_data = 4; 20 | PlayerEatFoodData eat_food_data = 5; 21 | PlayerAttackData attack_data = 6; 22 | PlayerEffectData effect_data = 7; 23 | PlayerGameModeData game_mode_data = 9; 24 | PlayerMotionData motion_data = 10; 25 | PlayerInputModeData input_mode_data = 11; 26 | PlayerHeldItemChangeData held_item_change_data = 12; 27 | PlayerLifeData life_data = 13; 28 | } 29 | } 30 | 31 | message PlayerActionData { 32 | EntityPositionData position = 1; 33 | PlayerAction action = 2; 34 | } 35 | 36 | message PlayerMoveData { 37 | EntityPositionData newPosition = 1; 38 | bool teleport = 2; 39 | } 40 | 41 | message PlayerPlaceBlockData { 42 | EntityPositionData position = 1; 43 | BlockData placedBlock = 2; 44 | } 45 | 46 | message PlayerBreakBlockData { 47 | EntityPositionData position = 1; 48 | BlockData brokenBlock = 2; 49 | } 50 | 51 | message PlayerEatFoodData { 52 | ConsumeStatus status = 2; 53 | } 54 | 55 | message PlayerAttackData { 56 | AttackData data = 1; 57 | bool damaged = 2; 58 | } 59 | 60 | message PlayerEffectData { 61 | repeated EffectFeature effect = 1; 62 | } 63 | 64 | message PlayerGameModeData { 65 | GameMode gameMode = 1; 66 | } 67 | 68 | message PlayerMotionData { 69 | EntityPositionData position = 1; 70 | Vec3f motion = 2; 71 | } 72 | 73 | message PlayerInputModeData { 74 | InputMode inputMode = 1; 75 | } 76 | 77 | message PlayerHeldItemChangeData { 78 | ItemData item = 1; 79 | } 80 | 81 | message PlayerLifeData { 82 | bool alive = 1; 83 | } 84 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/Vec2i.php: -------------------------------------------------------------------------------- 1 | xchange.Vec2i 13 | */ 14 | class Vec2i extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field int32 x = 1; 18 | */ 19 | protected $x = 0; 20 | /** 21 | * Generated from protobuf field int32 y = 2; 22 | */ 23 | protected $y = 0; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type int $x 32 | * @type int $y 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PrimitiveTypes::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field int32 x = 1; 42 | * @return int 43 | */ 44 | public function getX() 45 | { 46 | return $this->x; 47 | } 48 | 49 | /** 50 | * Generated from protobuf field int32 x = 1; 51 | * @param int $var 52 | * @return $this 53 | */ 54 | public function setX($var) 55 | { 56 | GPBUtil::checkInt32($var); 57 | $this->x = $var; 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Generated from protobuf field int32 y = 2; 64 | * @return int 65 | */ 66 | public function getY() 67 | { 68 | return $this->y; 69 | } 70 | 71 | /** 72 | * Generated from protobuf field int32 y = 2; 73 | * @param int $var 74 | * @return $this 75 | */ 76 | public function setY($var) 77 | { 78 | GPBUtil::checkInt32($var); 79 | $this->y = $var; 80 | 81 | return $this; 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/Vec2f.php: -------------------------------------------------------------------------------- 1 | xchange.Vec2f 13 | */ 14 | class Vec2f extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field float x = 1; 18 | */ 19 | protected $x = 0.0; 20 | /** 21 | * Generated from protobuf field float y = 2; 22 | */ 23 | protected $y = 0.0; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type float $x 32 | * @type float $y 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PrimitiveTypes::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field float x = 1; 42 | * @return float 43 | */ 44 | public function getX() 45 | { 46 | return $this->x; 47 | } 48 | 49 | /** 50 | * Generated from protobuf field float x = 1; 51 | * @param float $var 52 | * @return $this 53 | */ 54 | public function setX($var) 55 | { 56 | GPBUtil::checkFloat($var); 57 | $this->x = $var; 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Generated from protobuf field float y = 2; 64 | * @return float 65 | */ 66 | public function getY() 67 | { 68 | return $this->y; 69 | } 70 | 71 | /** 72 | * Generated from protobuf field float y = 2; 73 | * @param float $var 74 | * @return $this 75 | */ 76 | public function setY($var) 77 | { 78 | GPBUtil::checkFloat($var); 79 | $this->y = $var; 80 | 81 | return $this; 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/Player.php: -------------------------------------------------------------------------------- 1 | xchange.Player 13 | */ 14 | class Player extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.DeviceOS os = 1; 18 | */ 19 | protected $os = 0; 20 | /** 21 | * Generated from protobuf field string name = 2; 22 | */ 23 | protected $name = ''; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type int $os 32 | * @type string $name 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\Player::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.DeviceOS os = 1; 42 | * @return int 43 | */ 44 | public function getOs() 45 | { 46 | return $this->os; 47 | } 48 | 49 | /** 50 | * Generated from protobuf field .xchange.DeviceOS os = 1; 51 | * @param int $var 52 | * @return $this 53 | */ 54 | public function setOs($var) 55 | { 56 | GPBUtil::checkEnum($var, \prokits\xyron\DeviceOS::class); 57 | $this->os = $var; 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Generated from protobuf field string name = 2; 64 | * @return string 65 | */ 66 | public function getName() 67 | { 68 | return $this->name; 69 | } 70 | 71 | /** 72 | * Generated from protobuf field string name = 2; 73 | * @param string $var 74 | * @return $this 75 | */ 76 | public function setName($var) 77 | { 78 | GPBUtil::checkString($var, True); 79 | $this->name = $var; 80 | 81 | return $this; 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /java_protobuf/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | xyron 7 | com.github.blackjack200 8 | 0.0.1 9 | 10 | 4.0.0 11 | 12 | java_protobuf 13 | 14 | 15 | UTF-8 16 | 1.56.1 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | 24 | io.grpc 25 | grpc-bom 26 | ${grpc.version} 27 | pom 28 | import 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | javax.annotation 37 | javax.annotation-api 38 | 1.3.2 39 | 40 | 41 | 42 | io.grpc 43 | grpc-stub 44 | ${grpc.version} 45 | 46 | 47 | 48 | io.grpc 49 | grpc-protobuf 50 | ${grpc.version} 51 | 52 | 53 | io.grpc 54 | grpc-okhttp 55 | ${grpc.version} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "140ba843bc542e935ece8b6c86353e5a", 8 | "packages": [ 9 | { 10 | "name": "google/protobuf", 11 | "version": "v3.25.2", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/protocolbuffers/protobuf-php.git", 15 | "reference": "83ea4c147718666ce6a9b9332ac2aa588c9211eb" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/83ea4c147718666ce6a9b9332ac2aa588c9211eb", 20 | "reference": "83ea4c147718666ce6a9b9332ac2aa588c9211eb", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=7.0.0" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": ">=5.0.0" 28 | }, 29 | "suggest": { 30 | "ext-bcmath": "Need to support JSON deserialization" 31 | }, 32 | "type": "library", 33 | "autoload": { 34 | "psr-4": { 35 | "Google\\Protobuf\\": "src/Google/Protobuf", 36 | "GPBMetadata\\Google\\Protobuf\\": "src/GPBMetadata/Google/Protobuf" 37 | } 38 | }, 39 | "notification-url": "https://packagist.org/downloads/", 40 | "license": [ 41 | "BSD-3-Clause" 42 | ], 43 | "description": "proto library for PHP", 44 | "homepage": "https://developers.google.com/protocol-buffers/", 45 | "keywords": [ 46 | "proto" 47 | ], 48 | "support": { 49 | "source": "https://github.com/protocolbuffers/protobuf-php/tree/v3.25.2" 50 | }, 51 | "time": "2024-01-09T22:12:32+00:00" 52 | } 53 | ], 54 | "packages-dev": [], 55 | "aliases": [], 56 | "minimum-stability": "stable", 57 | "stability-flags": [], 58 | "prefer-stable": false, 59 | "prefer-lowest": false, 60 | "platform": [], 61 | "platform-dev": [], 62 | "plugin-api-version": "2.3.0" 63 | } 64 | -------------------------------------------------------------------------------- /nukkit_binding/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | xyron 7 | com.github.blackjack200 8 | 0.0.1 9 | 10 | 4.0.0 11 | 12 | nukkit_binding 13 | 14 | 15 | UTF-8 16 | 1.56.1 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | 24 | nukkitx-repo 25 | http://repo.nukkitx.com/main/ 26 | 27 | 28 | 29 | 30 | 31 | cn.nukkit 32 | nukkit 33 | 1.0-SNAPSHOT 34 | provided 35 | 36 | 37 | com.github.blackjack200 38 | java_protobuf 39 | 0.0.1 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.apache.maven.plugins 48 | maven-shade-plugin 49 | 3.2.1 50 | 51 | 52 | 53 | *:* 54 | 55 | 56 | false 57 | 58 | 59 | 60 | package 61 | 62 | shade 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerAttackData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerAttackData 13 | */ 14 | class PlayerAttackData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.AttackData data = 1; 18 | */ 19 | protected $data = null; 20 | /** 21 | * Generated from protobuf field bool damaged = 2; 22 | */ 23 | protected $damaged = false; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\AttackData $data 32 | * @type bool $damaged 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PlayerWrappers::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.AttackData data = 1; 42 | * @return \prokits\xyron\AttackData|null 43 | */ 44 | public function getData() 45 | { 46 | return $this->data; 47 | } 48 | 49 | public function hasData() 50 | { 51 | return isset($this->data); 52 | } 53 | 54 | public function clearData() 55 | { 56 | unset($this->data); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.AttackData data = 1; 61 | * @param \prokits\xyron\AttackData $var 62 | * @return $this 63 | */ 64 | public function setData($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\AttackData::class); 67 | $this->data = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field bool damaged = 2; 74 | * @return bool 75 | */ 76 | public function getDamaged() 77 | { 78 | return $this->damaged; 79 | } 80 | 81 | /** 82 | * Generated from protobuf field bool damaged = 2; 83 | * @param bool $var 84 | * @return $this 85 | */ 86 | public function setDamaged($var) 87 | { 88 | GPBUtil::checkBool($var); 89 | $this->damaged = $var; 90 | 91 | return $this; 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/main/proto/player.proto: -------------------------------------------------------------------------------- 1 | syntax = 'proto3'; 2 | 3 | option go_package = "xyron/"; 4 | option php_namespace = "prokits\\xyron"; 5 | option java_package = "com.github.blackjack200.xyron"; 6 | option java_generic_services = true; 7 | option php_generic_services = true; 8 | 9 | package xchange; 10 | 11 | import "primitive_types.proto"; 12 | 13 | enum GameMode { 14 | Survival = 0; 15 | Creative = 1; 16 | Adventure = 2; 17 | Spectator = 3; 18 | } 19 | 20 | enum InputMode { 21 | MouseKeyboard = 0; 22 | Touch = 1; 23 | Gamepad = 2; 24 | MotionController = 3; 25 | } 26 | 27 | enum DeviceOS { 28 | Android = 0; 29 | IOS = 1; 30 | OSX = 2; 31 | AMAZON = 3; 32 | GEAR_VR = 4; 33 | HOLOLENS = 5; 34 | WINDOWS_10 = 6; 35 | WIN32 = 7; 36 | DEDICATED = 8; 37 | TVOS = 9; 38 | PLAYSTATION = 10; 39 | NINTENDO = 11; 40 | XBOX = 12; 41 | WINDOWS_PHONE = 13; 42 | } 43 | 44 | enum PlayerAction { 45 | Jump = 0; 46 | Swing = 1; 47 | StartSprint = 2; 48 | StopSprint = 3; 49 | StartSneak = 4; 50 | StopSneak = 5; 51 | StartSprintFlying = 6; 52 | StopSprintFlying = 7; 53 | StartGliding = 8; 54 | StopGliding = 9; 55 | StartSwimming = 10; 56 | StopSwimming = 11; 57 | OpenInventory = 12; 58 | CloseInventory = 13; 59 | } 60 | 61 | enum DamageCause { 62 | Contact = 0; 63 | EntityAttack = 1; 64 | Projectile = 2; 65 | Suffocation = 3; 66 | Fall = 4; 67 | Fire = 5; 68 | FireTick = 6; 69 | Lava = 7; 70 | Drowning = 8; 71 | BlockExplosion = 9; 72 | EntityExplosion = 10; 73 | Void = 11; 74 | Suicide = 12; 75 | Magic = 13; 76 | Custom = 14; 77 | Starvation = 15; 78 | FallingBlock = 16; 79 | } 80 | 81 | enum BreakBlockStatus { 82 | StartBreak = 0; 83 | AbortBreak = 1; 84 | FinishBreak = 2; 85 | } 86 | 87 | enum ConsumeStatus { 88 | Start = 0; 89 | Stop = 1; 90 | } 91 | 92 | message EntityPositionData { 93 | Vec3f position = 1; 94 | Vec3f direction = 2; 95 | AxisAlignedBoundingBox boundingBox = 3; 96 | bool isImmobile = 4; 97 | bool isOnGround = 5; 98 | bool allowFlying = 6; 99 | bool isFlying = 7; 100 | bool haveGravity = 8; 101 | double movementSpeed = 9; 102 | bool wouldCollideVertically = 10; 103 | BlockData belowThatAffectMovement = 11; 104 | repeated BlockData collidedBlocks = 12; 105 | repeated BlockData intersectedBlocks = 13; 106 | } 107 | 108 | message AttackData { 109 | DamageCause cause = 1; 110 | EntityPositionData attacker = 2; 111 | EntityPositionData target = 3; 112 | } 113 | 114 | message Player { 115 | DeviceOS os = 1; 116 | string name = 2; 117 | } -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/AnticheatClient.php: -------------------------------------------------------------------------------- 1 | _simpleRequest('/xchange.Anticheat/AddPlayer', 28 | $argument, 29 | ['\prokits\xyron\PlayerReceipt', 'decode'], 30 | $metadata, $options); 31 | } 32 | 33 | /** 34 | * @param \prokits\xyron\PlayerReceipt $argument input argument 35 | * @param array $metadata metadata 36 | * @param array $options call options 37 | * @return \Grpc\UnaryCall 38 | */ 39 | public function RemovePlayer(\prokits\xyron\PlayerReceipt $argument, 40 | $metadata = [], $options = []) { 41 | return $this->_simpleRequest('/xchange.Anticheat/RemovePlayer', 42 | $argument, 43 | ['\Google\Protobuf\GPBEmpty', 'decode'], 44 | $metadata, $options); 45 | } 46 | 47 | /** 48 | * @param \prokits\xyron\ReportData $argument input argument 49 | * @param array $metadata metadata 50 | * @param array $options call options 51 | * @return \Grpc\UnaryCall 52 | */ 53 | public function Report(\prokits\xyron\ReportData $argument, 54 | $metadata = [], $options = []) { 55 | return $this->_simpleRequest('/xchange.Anticheat/Report', 56 | $argument, 57 | ['\prokits\xyron\ReportResponse', 'decode'], 58 | $metadata, $options); 59 | } 60 | 61 | /** 62 | * @param \prokits\xyron\BatchedReportData $argument input argument 63 | * @param array $metadata metadata 64 | * @param array $options call options 65 | * @return \Grpc\UnaryCall 66 | */ 67 | public function ReportBatched(\prokits\xyron\BatchedReportData $argument, 68 | $metadata = [], $options = []) { 69 | return $this->_simpleRequest('/xchange.Anticheat/ReportBatched', 70 | $argument, 71 | ['\prokits\xyron\BatchedReportResponse', 'decode'], 72 | $metadata, $options); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerMoveData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerMoveData 13 | */ 14 | class PlayerMoveData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.EntityPositionData newPosition = 1; 18 | */ 19 | protected $newPosition = null; 20 | /** 21 | * Generated from protobuf field bool teleport = 2; 22 | */ 23 | protected $teleport = false; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\EntityPositionData $newPosition 32 | * @type bool $teleport 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PlayerWrappers::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.EntityPositionData newPosition = 1; 42 | * @return \prokits\xyron\EntityPositionData|null 43 | */ 44 | public function getNewPosition() 45 | { 46 | return $this->newPosition; 47 | } 48 | 49 | public function hasNewPosition() 50 | { 51 | return isset($this->newPosition); 52 | } 53 | 54 | public function clearNewPosition() 55 | { 56 | unset($this->newPosition); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.EntityPositionData newPosition = 1; 61 | * @param \prokits\xyron\EntityPositionData $var 62 | * @return $this 63 | */ 64 | public function setNewPosition($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\EntityPositionData::class); 67 | $this->newPosition = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field bool teleport = 2; 74 | * @return bool 75 | */ 76 | public function getTeleport() 77 | { 78 | return $this->teleport; 79 | } 80 | 81 | /** 82 | * Generated from protobuf field bool teleport = 2; 83 | * @param bool $var 84 | * @return $this 85 | */ 86 | public function setTeleport($var) 87 | { 88 | GPBUtil::checkBool($var); 89 | $this->teleport = $var; 90 | 91 | return $this; 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /anticheat/violation_buffer.go: -------------------------------------------------------------------------------- 1 | package anticheat 2 | 3 | import ( 4 | "fmt" 5 | "github.com/blackjack200/xyron/xyron" 6 | "math" 7 | ) 8 | 9 | type ViolationBuffer struct { 10 | buf float64 11 | Max float64 12 | } 13 | 14 | func NewViolationBuffer(max float64) *ViolationBuffer { 15 | return &ViolationBuffer{Max: max} 16 | } 17 | 18 | func (b *ViolationBuffer) Possibility() float64 { 19 | return math.Min(1, b.buf/b.Max) 20 | } 21 | 22 | func (b *ViolationBuffer) PossibilityString() string { 23 | return fmt.Sprintf("%.3f%%", math.Min(1, b.buf/b.Max)*100) 24 | } 25 | 26 | func (b *ViolationBuffer) HandleMax(measured, expectedMax float64) { 27 | if measured > expectedMax { 28 | b.buf++ 29 | } 30 | } 31 | 32 | func (b *ViolationBuffer) HandleMaxRate(measured, expectedMax, rate float64) { 33 | if measured > expectedMax { 34 | b.buf++ 35 | } else { 36 | b.buf *= rate 37 | } 38 | } 39 | 40 | func (b *ViolationBuffer) Add() { 41 | b.buf++ 42 | } 43 | 44 | func (b *ViolationBuffer) HandleUnstable(measured, expectedMax float64) { 45 | if measured > expectedMax { 46 | b.buf++ 47 | } else { 48 | b.buf = 0 49 | } 50 | } 51 | 52 | func (b *ViolationBuffer) HandleUnstableRate(measured, expectedMax, rate float64) { 53 | if measured > expectedMax { 54 | b.buf++ 55 | } else { 56 | b.buf *= rate 57 | } 58 | } 59 | 60 | func (b *ViolationBuffer) HandleRelative(measured, expected, latitude float64) { 61 | if math.Abs(measured-expected) > latitude { 62 | b.buf++ 63 | } 64 | } 65 | 66 | func (b *ViolationBuffer) HandleRelativeUnstable(measured, expected, latitude float64) { 67 | b.HandleRelativeUnstableRate(measured, expected, latitude, 0) 68 | } 69 | 70 | func (b *ViolationBuffer) HandleRelativeUnstableRate(measured, expected, latitude, rate float64) { 71 | if math.Abs(measured-expected) > latitude { 72 | b.buf++ 73 | } else { 74 | b.buf *= rate 75 | } 76 | } 77 | 78 | type Evaluator struct { 79 | *ViolationBuffer 80 | MinValidPossibility float64 81 | MaxPossibilityAmbiguous float64 82 | } 83 | 84 | func NewEvaluator(max float64, minValidPossibility float64, maxPossibilityAmbiguous float64) *Evaluator { 85 | return &Evaluator{ 86 | ViolationBuffer: NewViolationBuffer(max), 87 | MinValidPossibility: minValidPossibility, 88 | MaxPossibilityAmbiguous: maxPossibilityAmbiguous, 89 | } 90 | } 91 | 92 | func (e *Evaluator) Evaluate() xyron.Judgement { 93 | possibility := e.Possibility() 94 | if possibility <= e.MinValidPossibility { 95 | return xyron.Judgement_DEBUG 96 | } 97 | if possibility <= e.MaxPossibilityAmbiguous { 98 | return xyron.Judgement_AMBIGUOUS 99 | } 100 | return xyron.Judgement_TRIGGER 101 | } 102 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerActionData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerActionData 13 | */ 14 | class PlayerActionData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 18 | */ 19 | protected $position = null; 20 | /** 21 | * Generated from protobuf field .xchange.PlayerAction action = 2; 22 | */ 23 | protected $action = 0; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\EntityPositionData $position 32 | * @type int $action 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PlayerWrappers::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 42 | * @return \prokits\xyron\EntityPositionData|null 43 | */ 44 | public function getPosition() 45 | { 46 | return $this->position; 47 | } 48 | 49 | public function hasPosition() 50 | { 51 | return isset($this->position); 52 | } 53 | 54 | public function clearPosition() 55 | { 56 | unset($this->position); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 61 | * @param \prokits\xyron\EntityPositionData $var 62 | * @return $this 63 | */ 64 | public function setPosition($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\EntityPositionData::class); 67 | $this->position = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field .xchange.PlayerAction action = 2; 74 | * @return int 75 | */ 76 | public function getAction() 77 | { 78 | return $this->action; 79 | } 80 | 81 | /** 82 | * Generated from protobuf field .xchange.PlayerAction action = 2; 83 | * @param int $var 84 | * @return $this 85 | */ 86 | public function setAction($var) 87 | { 88 | GPBUtil::checkEnum($var, \prokits\xyron\PlayerAction::class); 89 | $this->action = $var; 90 | 91 | return $this; 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/Vec3i.php: -------------------------------------------------------------------------------- 1 | xchange.Vec3i 13 | */ 14 | class Vec3i extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field int32 x = 1; 18 | */ 19 | protected $x = 0; 20 | /** 21 | * Generated from protobuf field int32 y = 2; 22 | */ 23 | protected $y = 0; 24 | /** 25 | * Generated from protobuf field int32 z = 3; 26 | */ 27 | protected $z = 0; 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param array $data { 33 | * Optional. Data for populating the Message object. 34 | * 35 | * @type int $x 36 | * @type int $y 37 | * @type int $z 38 | * } 39 | */ 40 | public function __construct($data = NULL) { 41 | \GPBMetadata\PrimitiveTypes::initOnce(); 42 | parent::__construct($data); 43 | } 44 | 45 | /** 46 | * Generated from protobuf field int32 x = 1; 47 | * @return int 48 | */ 49 | public function getX() 50 | { 51 | return $this->x; 52 | } 53 | 54 | /** 55 | * Generated from protobuf field int32 x = 1; 56 | * @param int $var 57 | * @return $this 58 | */ 59 | public function setX($var) 60 | { 61 | GPBUtil::checkInt32($var); 62 | $this->x = $var; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * Generated from protobuf field int32 y = 2; 69 | * @return int 70 | */ 71 | public function getY() 72 | { 73 | return $this->y; 74 | } 75 | 76 | /** 77 | * Generated from protobuf field int32 y = 2; 78 | * @param int $var 79 | * @return $this 80 | */ 81 | public function setY($var) 82 | { 83 | GPBUtil::checkInt32($var); 84 | $this->y = $var; 85 | 86 | return $this; 87 | } 88 | 89 | /** 90 | * Generated from protobuf field int32 z = 3; 91 | * @return int 92 | */ 93 | public function getZ() 94 | { 95 | return $this->z; 96 | } 97 | 98 | /** 99 | * Generated from protobuf field int32 z = 3; 100 | * @param int $var 101 | * @return $this 102 | */ 103 | public function setZ($var) 104 | { 105 | GPBUtil::checkInt32($var); 106 | $this->z = $var; 107 | 108 | return $this; 109 | } 110 | 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/Vec3f.php: -------------------------------------------------------------------------------- 1 | xchange.Vec3f 13 | */ 14 | class Vec3f extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field float x = 1; 18 | */ 19 | protected $x = 0.0; 20 | /** 21 | * Generated from protobuf field float y = 2; 22 | */ 23 | protected $y = 0.0; 24 | /** 25 | * Generated from protobuf field float z = 3; 26 | */ 27 | protected $z = 0.0; 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param array $data { 33 | * Optional. Data for populating the Message object. 34 | * 35 | * @type float $x 36 | * @type float $y 37 | * @type float $z 38 | * } 39 | */ 40 | public function __construct($data = NULL) { 41 | \GPBMetadata\PrimitiveTypes::initOnce(); 42 | parent::__construct($data); 43 | } 44 | 45 | /** 46 | * Generated from protobuf field float x = 1; 47 | * @return float 48 | */ 49 | public function getX() 50 | { 51 | return $this->x; 52 | } 53 | 54 | /** 55 | * Generated from protobuf field float x = 1; 56 | * @param float $var 57 | * @return $this 58 | */ 59 | public function setX($var) 60 | { 61 | GPBUtil::checkFloat($var); 62 | $this->x = $var; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * Generated from protobuf field float y = 2; 69 | * @return float 70 | */ 71 | public function getY() 72 | { 73 | return $this->y; 74 | } 75 | 76 | /** 77 | * Generated from protobuf field float y = 2; 78 | * @param float $var 79 | * @return $this 80 | */ 81 | public function setY($var) 82 | { 83 | GPBUtil::checkFloat($var); 84 | $this->y = $var; 85 | 86 | return $this; 87 | } 88 | 89 | /** 90 | * Generated from protobuf field float z = 3; 91 | * @return float 92 | */ 93 | public function getZ() 94 | { 95 | return $this->z; 96 | } 97 | 98 | /** 99 | * Generated from protobuf field float z = 3; 100 | * @param float $var 101 | * @return $this 102 | */ 103 | public function setZ($var) 104 | { 105 | GPBUtil::checkFloat($var); 106 | $this->z = $var; 107 | 108 | return $this; 109 | } 110 | 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/AxisAlignedBoundingBox.php: -------------------------------------------------------------------------------- 1 | xchange.AxisAlignedBoundingBox 13 | */ 14 | class AxisAlignedBoundingBox extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.Vec3f min = 1; 18 | */ 19 | protected $min = null; 20 | /** 21 | * Generated from protobuf field .xchange.Vec3f max = 2; 22 | */ 23 | protected $max = null; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\Vec3f $min 32 | * @type \prokits\xyron\Vec3f $max 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PrimitiveTypes::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.Vec3f min = 1; 42 | * @return \prokits\xyron\Vec3f|null 43 | */ 44 | public function getMin() 45 | { 46 | return $this->min; 47 | } 48 | 49 | public function hasMin() 50 | { 51 | return isset($this->min); 52 | } 53 | 54 | public function clearMin() 55 | { 56 | unset($this->min); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.Vec3f min = 1; 61 | * @param \prokits\xyron\Vec3f $var 62 | * @return $this 63 | */ 64 | public function setMin($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\Vec3f::class); 67 | $this->min = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field .xchange.Vec3f max = 2; 74 | * @return \prokits\xyron\Vec3f|null 75 | */ 76 | public function getMax() 77 | { 78 | return $this->max; 79 | } 80 | 81 | public function hasMax() 82 | { 83 | return isset($this->max); 84 | } 85 | 86 | public function clearMax() 87 | { 88 | unset($this->max); 89 | } 90 | 91 | /** 92 | * Generated from protobuf field .xchange.Vec3f max = 2; 93 | * @param \prokits\xyron\Vec3f $var 94 | * @return $this 95 | */ 96 | public function setMax($var) 97 | { 98 | GPBUtil::checkMessage($var, \prokits\xyron\Vec3f::class); 99 | $this->max = $var; 100 | 101 | return $this; 102 | } 103 | 104 | } 105 | 106 | -------------------------------------------------------------------------------- /anticheat/util.go: -------------------------------------------------------------------------------- 1 | package anticheat 2 | 3 | import ( 4 | "fmt" 5 | "github.com/blackjack200/xyron/xyron" 6 | "github.com/df-mc/dragonfly/server/block/cube" 7 | "github.com/go-gl/mathgl/mgl64" 8 | "math" 9 | "sort" 10 | ) 11 | 12 | var internalIdCounter = int64(0) 13 | 14 | func internalId(name string) string { 15 | internalIdCounter++ 16 | return fmt.Sprintf("%v_%v", name, internalIdCounter) 17 | } 18 | 19 | type BufferedData[T any] struct { 20 | prev, cur T 21 | } 22 | 23 | func NewBufferedData[T any](cur T) *BufferedData[T] { 24 | return &BufferedData[T]{prev: cur, cur: cur} 25 | } 26 | 27 | func (b *BufferedData[T]) Previous() T { 28 | return b.prev 29 | } 30 | 31 | func (b *BufferedData[T]) Current() T { 32 | return b.cur 33 | } 34 | 35 | func (b *BufferedData[T]) Set(v T) { 36 | b.prev, b.cur = b.cur, v 37 | } 38 | 39 | type TimestampedData[T any] struct { 40 | t int64 41 | v T 42 | } 43 | 44 | func (t TimestampedData[T]) Timestamp() int64 { 45 | return t.t 46 | } 47 | 48 | func (t TimestampedData[T]) Duration(tick int64) int64 { 49 | return tick - t.Timestamp() 50 | } 51 | 52 | func (t TimestampedData[T]) Get() T { 53 | return t.v 54 | } 55 | 56 | func NewTimestampedData[T any](timestamp int64, v T) TimestampedData[T] { 57 | return TimestampedData[T]{t: timestamp, v: v} 58 | } 59 | 60 | type BufferedTimestampedData[T any] BufferedData[TimestampedData[T]] 61 | 62 | func (b *BufferedTimestampedData[T]) Previous() TimestampedData[T] { 63 | return b.prev 64 | } 65 | 66 | func (b *BufferedTimestampedData[T]) Current() TimestampedData[T] { 67 | return b.cur 68 | } 69 | 70 | func (b *BufferedTimestampedData[T]) Set(timestamp int64, v T) { 71 | b.prev, b.cur = b.cur, NewTimestampedData(timestamp, v) 72 | } 73 | 74 | func NewBufferedTimestampedData[T any](v T) *BufferedTimestampedData[T] { 75 | p := NewTimestampedData[T](0, v) 76 | return &BufferedTimestampedData[T]{ 77 | prev: p, 78 | cur: p, 79 | } 80 | } 81 | 82 | type ComparableSlice[T ~int | 83 | ~int8 | ~int32 | ~int64 | 84 | ~uint8 | ~uint32 | ~uint64 | 85 | ~float32 | ~float64, 86 | ] []T 87 | 88 | func (x ComparableSlice[T]) Len() int { return len(x) } 89 | func (x ComparableSlice[T]) Less(i, j int) bool { return x[i] < x[j] } 90 | func (x ComparableSlice[T]) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 91 | 92 | // Sort is a convenience method: x.Sort() calls Sort(x). 93 | func (x ComparableSlice[T]) Sort() { sort.Sort(x) } 94 | 95 | func toVec3(pos *xyron.Vec3F) mgl64.Vec3 { 96 | return mgl64.Vec3{ 97 | float64(pos.X), 98 | float64(pos.Y), 99 | float64(pos.Z), 100 | } 101 | } 102 | 103 | func Vec3ToRotation(vec3 mgl64.Vec3) cube.Rotation { 104 | pitchRad := math.Asin(-vec3.Y()) 105 | m := math.Cos(pitchRad) 106 | yawRad := math.Acos(vec3.Z() / m) 107 | return cube.Rotation{ 108 | mgl64.RadToDeg(yawRad), 109 | mgl64.RadToDeg(pitchRad), 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/BatchedReportResponseEntry.php: -------------------------------------------------------------------------------- 1 | xchange.BatchedReportResponseEntry 13 | */ 14 | class BatchedReportResponseEntry extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.PlayerReceipt player = 1; 18 | */ 19 | protected $player = null; 20 | /** 21 | * Generated from protobuf field repeated .xchange.JudgementData judgements = 2; 22 | */ 23 | private $judgements; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\PlayerReceipt $player 32 | * @type array<\prokits\xyron\JudgementData>|\Google\Protobuf\Internal\RepeatedField $judgements 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\Xchange::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.PlayerReceipt player = 1; 42 | * @return \prokits\xyron\PlayerReceipt|null 43 | */ 44 | public function getPlayer() 45 | { 46 | return $this->player; 47 | } 48 | 49 | public function hasPlayer() 50 | { 51 | return isset($this->player); 52 | } 53 | 54 | public function clearPlayer() 55 | { 56 | unset($this->player); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.PlayerReceipt player = 1; 61 | * @param \prokits\xyron\PlayerReceipt $var 62 | * @return $this 63 | */ 64 | public function setPlayer($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\PlayerReceipt::class); 67 | $this->player = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field repeated .xchange.JudgementData judgements = 2; 74 | * @return \Google\Protobuf\Internal\RepeatedField 75 | */ 76 | public function getJudgements() 77 | { 78 | return $this->judgements; 79 | } 80 | 81 | /** 82 | * Generated from protobuf field repeated .xchange.JudgementData judgements = 2; 83 | * @param array<\prokits\xyron\JudgementData>|\Google\Protobuf\Internal\RepeatedField $var 84 | * @return $this 85 | */ 86 | public function setJudgements($var) 87 | { 88 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\JudgementData::class); 89 | $this->judgements = $arr; 90 | 91 | return $this; 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/BlockData.php: -------------------------------------------------------------------------------- 1 | xchange.BlockData 13 | */ 14 | class BlockData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.BlockFeature feature = 1; 18 | */ 19 | protected $feature = null; 20 | /** 21 | * Generated from protobuf field .xchange.Vec3i position = 2; 22 | */ 23 | protected $position = null; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\BlockFeature $feature 32 | * @type \prokits\xyron\Vec3i $position 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PrimitiveTypes::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.BlockFeature feature = 1; 42 | * @return \prokits\xyron\BlockFeature|null 43 | */ 44 | public function getFeature() 45 | { 46 | return $this->feature; 47 | } 48 | 49 | public function hasFeature() 50 | { 51 | return isset($this->feature); 52 | } 53 | 54 | public function clearFeature() 55 | { 56 | unset($this->feature); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.BlockFeature feature = 1; 61 | * @param \prokits\xyron\BlockFeature $var 62 | * @return $this 63 | */ 64 | public function setFeature($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\BlockFeature::class); 67 | $this->feature = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field .xchange.Vec3i position = 2; 74 | * @return \prokits\xyron\Vec3i|null 75 | */ 76 | public function getPosition() 77 | { 78 | return $this->position; 79 | } 80 | 81 | public function hasPosition() 82 | { 83 | return isset($this->position); 84 | } 85 | 86 | public function clearPosition() 87 | { 88 | unset($this->position); 89 | } 90 | 91 | /** 92 | * Generated from protobuf field .xchange.Vec3i position = 2; 93 | * @param \prokits\xyron\Vec3i $var 94 | * @return $this 95 | */ 96 | public function setPosition($var) 97 | { 98 | GPBUtil::checkMessage($var, \prokits\xyron\Vec3i::class); 99 | $this->position = $var; 100 | 101 | return $this; 102 | } 103 | 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerMotionData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerMotionData 13 | */ 14 | class PlayerMotionData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 18 | */ 19 | protected $position = null; 20 | /** 21 | * Generated from protobuf field .xchange.Vec3f motion = 2; 22 | */ 23 | protected $motion = null; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\EntityPositionData $position 32 | * @type \prokits\xyron\Vec3f $motion 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PlayerWrappers::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 42 | * @return \prokits\xyron\EntityPositionData|null 43 | */ 44 | public function getPosition() 45 | { 46 | return $this->position; 47 | } 48 | 49 | public function hasPosition() 50 | { 51 | return isset($this->position); 52 | } 53 | 54 | public function clearPosition() 55 | { 56 | unset($this->position); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 61 | * @param \prokits\xyron\EntityPositionData $var 62 | * @return $this 63 | */ 64 | public function setPosition($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\EntityPositionData::class); 67 | $this->position = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field .xchange.Vec3f motion = 2; 74 | * @return \prokits\xyron\Vec3f|null 75 | */ 76 | public function getMotion() 77 | { 78 | return $this->motion; 79 | } 80 | 81 | public function hasMotion() 82 | { 83 | return isset($this->motion); 84 | } 85 | 86 | public function clearMotion() 87 | { 88 | unset($this->motion); 89 | } 90 | 91 | /** 92 | * Generated from protobuf field .xchange.Vec3f motion = 2; 93 | * @param \prokits\xyron\Vec3f $var 94 | * @return $this 95 | */ 96 | public function setMotion($var) 97 | { 98 | GPBUtil::checkMessage($var, \prokits\xyron\Vec3f::class); 99 | $this->motion = $var; 100 | 101 | return $this; 102 | } 103 | 104 | } 105 | 106 | -------------------------------------------------------------------------------- /implementation/speed_ground.go: -------------------------------------------------------------------------------- 1 | package implementation 2 | 3 | import ( 4 | "fmt" 5 | "github.com/blackjack200/xyron/anticheat" 6 | "github.com/blackjack200/xyron/xyron" 7 | "github.com/go-gl/mathgl/mgl64" 8 | "math" 9 | ) 10 | 11 | type SpeedGround struct { 12 | *anticheat.Evaluator 13 | PredictionLatitude float64 14 | UnstableRate float64 15 | } 16 | 17 | var _ anticheat.MoveDataHandler = &SpeedGround{} 18 | 19 | func init() { 20 | register(func() any { 21 | return &SpeedGround{ 22 | anticheat.NewEvaluator(80, 0.75, 0.96), 23 | 0.45, 24 | 0.997, 25 | } 26 | }) 27 | } 28 | 29 | func (g *SpeedGround) HandleMoveData(p *anticheat.InternalPlayer, data *xyron.PlayerMoveData) *xyron.JudgementData { 30 | if isPlayerFreeFalling(p, data.NewPosition) { 31 | return nil 32 | } 33 | if p.OnGroundTick < 5 { 34 | return nil 35 | } 36 | if p.Location.Previous() == nil { 37 | return nil 38 | } 39 | oldPos := toVec3(p.Location.Previous().Position) 40 | pos := toVec3(p.Location.Current().Position) 41 | delta := pos.Sub(oldPos) 42 | 43 | futurePos := toVec3(data.NewPosition.Position) 44 | deltaFuture := futurePos.Sub(oldPos) 45 | 46 | //FIXME a huge amount of inaccuracies, currently assuming the inaccuracies < 0.45 47 | 48 | if isZero(futurePos.Sub(pos).Len()) { 49 | return nil 50 | } 51 | 52 | slipperness := getSlipperiness(p.Location.Current().BelowThatAffectMovement.Feature) 53 | 54 | //TODO movement direction: https://www.mcpk.wiki/wiki/Horizontal_Movement_Formulas/zh 55 | // currently we use maximum value as possible 56 | movementFactor := 0.98 57 | if p.Sprinting.Current().Get() { 58 | movementFactor = 1.3 59 | } 60 | if p.Sneaking.Current().Get() { 61 | movementFactor = 0.3 * 0.98 * math.Sqrt(2) 62 | } 63 | 64 | effectsFactor := 1.0 65 | 66 | effectsFactor *= 1 + 0.2*p.Effect(func(f *xyron.EffectFeature) bool { 67 | return f.IsSpeed 68 | }) 69 | 70 | effectsFactor *= 1 - 0.15*p.Effect(func(f *xyron.EffectFeature) bool { 71 | return f.IsSlowness 72 | }) 73 | 74 | slippernessFactor := math.Pow(0.6/slipperness, 3) 75 | predictedMaxDX := delta.X()*slipperness*0.91 + 0.1*movementFactor*effectsFactor*slippernessFactor 76 | predictedMaxDZ := delta.Z()*slipperness*0.91 + 0.1*movementFactor*effectsFactor*slippernessFactor 77 | pred := mgl64.Vec2{predictedMaxDX, predictedMaxDZ}.Len() 78 | measured := mgl64.Vec2{deltaFuture.X(), deltaFuture.Z()}.Len() 79 | 80 | g.HandleRelativeUnstableRate(measured, pred, g.PredictionLatitude, g.UnstableRate) 81 | 82 | equalness := math.Abs(measured - pred) 83 | return &xyron.JudgementData{ 84 | Type: "SpeedGround", 85 | Judgement: g.Evaluate(), 86 | Message: fmt.Sprintf("p:%v pred-xz:%.5f xz:%.5f delta:%.5f", g.PossibilityString(), measured, pred, equalness), 87 | } 88 | } 89 | 90 | func getSlipperiness(feature *xyron.BlockFeature) float64 { 91 | sliperness := 0.6 92 | if feature.IsAir { 93 | sliperness = 1.0 94 | } 95 | if feature.IsSlime { 96 | sliperness = 0.8 97 | } 98 | if feature.IsIce { 99 | sliperness = 0.98 100 | } 101 | return sliperness 102 | } 103 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/AddPlayerRequest.php: -------------------------------------------------------------------------------- 1 | xchange.AddPlayerRequest 13 | */ 14 | class AddPlayerRequest extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.Player player = 1; 18 | */ 19 | protected $player = null; 20 | /** 21 | *timestamp->report data 22 | * 23 | * Generated from protobuf field map data = 2; 24 | */ 25 | private $data; 26 | 27 | /** 28 | * Constructor. 29 | * 30 | * @param array $data { 31 | * Optional. Data for populating the Message object. 32 | * 33 | * @type \prokits\xyron\Player $player 34 | * @type array|\Google\Protobuf\Internal\MapField $data 35 | * timestamp->report data 36 | * } 37 | */ 38 | public function __construct($data = NULL) { 39 | \GPBMetadata\Xchange::initOnce(); 40 | parent::__construct($data); 41 | } 42 | 43 | /** 44 | * Generated from protobuf field .xchange.Player player = 1; 45 | * @return \prokits\xyron\Player|null 46 | */ 47 | public function getPlayer() 48 | { 49 | return $this->player; 50 | } 51 | 52 | public function hasPlayer() 53 | { 54 | return isset($this->player); 55 | } 56 | 57 | public function clearPlayer() 58 | { 59 | unset($this->player); 60 | } 61 | 62 | /** 63 | * Generated from protobuf field .xchange.Player player = 1; 64 | * @param \prokits\xyron\Player $var 65 | * @return $this 66 | */ 67 | public function setPlayer($var) 68 | { 69 | GPBUtil::checkMessage($var, \prokits\xyron\Player::class); 70 | $this->player = $var; 71 | 72 | return $this; 73 | } 74 | 75 | /** 76 | *timestamp->report data 77 | * 78 | * Generated from protobuf field map data = 2; 79 | * @return \Google\Protobuf\Internal\MapField 80 | */ 81 | public function getData() 82 | { 83 | return $this->data; 84 | } 85 | 86 | /** 87 | *timestamp->report data 88 | * 89 | * Generated from protobuf field map data = 2; 90 | * @param array|\Google\Protobuf\Internal\MapField $var 91 | * @return $this 92 | */ 93 | public function setData($var) 94 | { 95 | $arr = GPBUtil::checkMapField($var, \Google\Protobuf\Internal\GPBType::INT64, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\TimestampedReportData::class); 96 | $this->data = $arr; 97 | 98 | return $this; 99 | } 100 | 101 | } 102 | 103 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/JudgementData.php: -------------------------------------------------------------------------------- 1 | xchange.JudgementData 13 | */ 14 | class JudgementData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field string type = 1; 18 | */ 19 | protected $type = ''; 20 | /** 21 | * Generated from protobuf field .xchange.Judgement judgement = 2; 22 | */ 23 | protected $judgement = 0; 24 | /** 25 | * Generated from protobuf field string message = 3; 26 | */ 27 | protected $message = ''; 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param array $data { 33 | * Optional. Data for populating the Message object. 34 | * 35 | * @type string $type 36 | * @type int $judgement 37 | * @type string $message 38 | * } 39 | */ 40 | public function __construct($data = NULL) { 41 | \GPBMetadata\Xchange::initOnce(); 42 | parent::__construct($data); 43 | } 44 | 45 | /** 46 | * Generated from protobuf field string type = 1; 47 | * @return string 48 | */ 49 | public function getType() 50 | { 51 | return $this->type; 52 | } 53 | 54 | /** 55 | * Generated from protobuf field string type = 1; 56 | * @param string $var 57 | * @return $this 58 | */ 59 | public function setType($var) 60 | { 61 | GPBUtil::checkString($var, True); 62 | $this->type = $var; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * Generated from protobuf field .xchange.Judgement judgement = 2; 69 | * @return int 70 | */ 71 | public function getJudgement() 72 | { 73 | return $this->judgement; 74 | } 75 | 76 | /** 77 | * Generated from protobuf field .xchange.Judgement judgement = 2; 78 | * @param int $var 79 | * @return $this 80 | */ 81 | public function setJudgement($var) 82 | { 83 | GPBUtil::checkEnum($var, \prokits\xyron\Judgement::class); 84 | $this->judgement = $var; 85 | 86 | return $this; 87 | } 88 | 89 | /** 90 | * Generated from protobuf field string message = 3; 91 | * @return string 92 | */ 93 | public function getMessage() 94 | { 95 | return $this->message; 96 | } 97 | 98 | /** 99 | * Generated from protobuf field string message = 3; 100 | * @param string $var 101 | * @return $this 102 | */ 103 | public function setMessage($var) 104 | { 105 | GPBUtil::checkString($var, True); 106 | $this->message = $var; 107 | 108 | return $this; 109 | } 110 | 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerBreakBlockData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerBreakBlockData 13 | */ 14 | class PlayerBreakBlockData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 18 | */ 19 | protected $position = null; 20 | /** 21 | * Generated from protobuf field .xchange.BlockData brokenBlock = 2; 22 | */ 23 | protected $brokenBlock = null; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\EntityPositionData $position 32 | * @type \prokits\xyron\BlockData $brokenBlock 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PlayerWrappers::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 42 | * @return \prokits\xyron\EntityPositionData|null 43 | */ 44 | public function getPosition() 45 | { 46 | return $this->position; 47 | } 48 | 49 | public function hasPosition() 50 | { 51 | return isset($this->position); 52 | } 53 | 54 | public function clearPosition() 55 | { 56 | unset($this->position); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 61 | * @param \prokits\xyron\EntityPositionData $var 62 | * @return $this 63 | */ 64 | public function setPosition($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\EntityPositionData::class); 67 | $this->position = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field .xchange.BlockData brokenBlock = 2; 74 | * @return \prokits\xyron\BlockData|null 75 | */ 76 | public function getBrokenBlock() 77 | { 78 | return $this->brokenBlock; 79 | } 80 | 81 | public function hasBrokenBlock() 82 | { 83 | return isset($this->brokenBlock); 84 | } 85 | 86 | public function clearBrokenBlock() 87 | { 88 | unset($this->brokenBlock); 89 | } 90 | 91 | /** 92 | * Generated from protobuf field .xchange.BlockData brokenBlock = 2; 93 | * @param \prokits\xyron\BlockData $var 94 | * @return $this 95 | */ 96 | public function setBrokenBlock($var) 97 | { 98 | GPBUtil::checkMessage($var, \prokits\xyron\BlockData::class); 99 | $this->brokenBlock = $var; 100 | 101 | return $this; 102 | } 103 | 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerPlaceBlockData.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerPlaceBlockData 13 | */ 14 | class PlayerPlaceBlockData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 18 | */ 19 | protected $position = null; 20 | /** 21 | * Generated from protobuf field .xchange.BlockData placedBlock = 2; 22 | */ 23 | protected $placedBlock = null; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param array $data { 29 | * Optional. Data for populating the Message object. 30 | * 31 | * @type \prokits\xyron\EntityPositionData $position 32 | * @type \prokits\xyron\BlockData $placedBlock 33 | * } 34 | */ 35 | public function __construct($data = NULL) { 36 | \GPBMetadata\PlayerWrappers::initOnce(); 37 | parent::__construct($data); 38 | } 39 | 40 | /** 41 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 42 | * @return \prokits\xyron\EntityPositionData|null 43 | */ 44 | public function getPosition() 45 | { 46 | return $this->position; 47 | } 48 | 49 | public function hasPosition() 50 | { 51 | return isset($this->position); 52 | } 53 | 54 | public function clearPosition() 55 | { 56 | unset($this->position); 57 | } 58 | 59 | /** 60 | * Generated from protobuf field .xchange.EntityPositionData position = 1; 61 | * @param \prokits\xyron\EntityPositionData $var 62 | * @return $this 63 | */ 64 | public function setPosition($var) 65 | { 66 | GPBUtil::checkMessage($var, \prokits\xyron\EntityPositionData::class); 67 | $this->position = $var; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Generated from protobuf field .xchange.BlockData placedBlock = 2; 74 | * @return \prokits\xyron\BlockData|null 75 | */ 76 | public function getPlacedBlock() 77 | { 78 | return $this->placedBlock; 79 | } 80 | 81 | public function hasPlacedBlock() 82 | { 83 | return isset($this->placedBlock); 84 | } 85 | 86 | public function clearPlacedBlock() 87 | { 88 | unset($this->placedBlock); 89 | } 90 | 91 | /** 92 | * Generated from protobuf field .xchange.BlockData placedBlock = 2; 93 | * @param \prokits\xyron\BlockData $var 94 | * @return $this 95 | */ 96 | public function setPlacedBlock($var) 97 | { 98 | GPBUtil::checkMessage($var, \prokits\xyron\BlockData::class); 99 | $this->placedBlock = $var; 100 | 101 | return $this; 102 | } 103 | 104 | } 105 | 106 | -------------------------------------------------------------------------------- /implementation/gravity.go: -------------------------------------------------------------------------------- 1 | package implementation 2 | 3 | import ( 4 | "fmt" 5 | "github.com/blackjack200/xyron/anticheat" 6 | "github.com/blackjack200/xyron/xyron" 7 | "math" 8 | ) 9 | 10 | type Gravity struct { 11 | *anticheat.Evaluator 12 | PredictionLatitude float64 13 | UnstableRate float64 14 | } 15 | 16 | var _ anticheat.MoveDataHandler = &Gravity{} 17 | 18 | func init() { 19 | register(func() any { 20 | return &Gravity{ 21 | anticheat.NewEvaluator(80, 0.75, 0.96), 22 | 0.005, 23 | 0.997, 24 | } 25 | }) 26 | } 27 | 28 | func (g *Gravity) HandleMoveData(p *anticheat.InternalPlayer, data *xyron.PlayerMoveData) *xyron.JudgementData { 29 | if !isPlayerFreeFalling(p, data.NewPosition) { 30 | return nil 31 | } 32 | if p.Location.Previous() == nil { 33 | return nil 34 | } 35 | oldPos := toVec3(p.Location.Previous().Position) 36 | pos := toVec3(p.Location.Current().Position) 37 | deltaY := pos.Sub(oldPos).Y() 38 | 39 | futurePos := toVec3(data.NewPosition.Position) 40 | measuredFutureDeltaY := futurePos.Sub(pos).Y() 41 | if isZero(futurePos.Sub(pos).Len()) { 42 | return nil 43 | } 44 | 45 | predictedDeltaY := g.predictDeltaY(p, deltaY) 46 | 47 | if !p.Location.Current().IsFlying && 48 | !data.NewPosition.IsFlying && 49 | !p.Location.Current().AllowFlying { 50 | g.HandleRelativeUnstableRate(measuredFutureDeltaY, predictedDeltaY, g.PredictionLatitude, g.UnstableRate) 51 | } 52 | 53 | equalness := math.Abs(measuredFutureDeltaY - predictedDeltaY) 54 | return &xyron.JudgementData{ 55 | Type: "Gravity", 56 | Judgement: g.Evaluate(), 57 | Message: fmt.Sprintf("p:%v pred-dy:%.5f dy:%.5f delta:%.5f", g.PossibilityString(), predictedDeltaY, deltaY, equalness), 58 | } 59 | } 60 | 61 | // predictDeltaY https://github.com/Blackjack200/minecraft_client_1_16_2/blob/master/net/minecraft/world/entity/LivingEntity.java#L1891-1911 62 | func (g *Gravity) predictDeltaY(p *anticheat.InternalPlayer, prevDeltaY float64) float64 { 63 | predictedDeltaY := prevDeltaY 64 | if amp := p.Effect(func(f *xyron.EffectFeature) bool { 65 | return f.IsLevitation 66 | }); amp != 0 { 67 | predictedDeltaY += (0.05*(amp+1) - prevDeltaY) * 0.2 68 | } else if p.Location.Current().HaveGravity { 69 | predictedDeltaY -= calculateGravity(p) 70 | } 71 | predictedDeltaY *= 0.98 72 | 73 | //FIXME stuck block prediction not works at all 74 | 75 | //Cobweb https://github.com/Blackjack200/minecraft_client_1_16_2/blob/master/net/minecraft/world/entity/Entity.java#L516 76 | //https://github.com/Blackjack200/minecraft_client_1_16_2/blob/c7f87b96efaeb477d9604354aa23ada0eb637ec6/net/minecraft/world/level/block/WebBlock.java#L17C1 77 | if p.InCobweb.Current().Get() { 78 | println("COB") 79 | predictedDeltaY *= 0.05 80 | } 81 | 82 | //SweetBerry https://github.com/Blackjack200/minecraft_client_1_16_2/blob/c7f87b96efaeb477d9604354aa23ada0eb637ec6/net/minecraft/world/level/block/SweetBerryBushBlock.java#L73 83 | if p.InSweetBerry.Current().Get() { 84 | predictedDeltaY *= 0.75 85 | } 86 | 87 | return predictedDeltaY 88 | } 89 | 90 | func calculateGravity(p *anticheat.InternalPlayer) float64 { 91 | gravity := 0.08 92 | if !p.OnGround.Current().Get() && p.Effect(func(f *xyron.EffectFeature) bool { 93 | return f.IsSlowFalling 94 | }) != 0 { 95 | gravity = 0.01 96 | } 97 | return gravity 98 | } 99 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/DeviceOS.php: -------------------------------------------------------------------------------- 1 | xchange.DeviceOS 11 | */ 12 | class DeviceOS 13 | { 14 | /** 15 | * Generated from protobuf enum Android = 0; 16 | */ 17 | const Android = 0; 18 | /** 19 | * Generated from protobuf enum IOS = 1; 20 | */ 21 | const IOS = 1; 22 | /** 23 | * Generated from protobuf enum OSX = 2; 24 | */ 25 | const OSX = 2; 26 | /** 27 | * Generated from protobuf enum AMAZON = 3; 28 | */ 29 | const AMAZON = 3; 30 | /** 31 | * Generated from protobuf enum GEAR_VR = 4; 32 | */ 33 | const GEAR_VR = 4; 34 | /** 35 | * Generated from protobuf enum HOLOLENS = 5; 36 | */ 37 | const HOLOLENS = 5; 38 | /** 39 | * Generated from protobuf enum WINDOWS_10 = 6; 40 | */ 41 | const WINDOWS_10 = 6; 42 | /** 43 | * Generated from protobuf enum WIN32 = 7; 44 | */ 45 | const WIN32 = 7; 46 | /** 47 | * Generated from protobuf enum DEDICATED = 8; 48 | */ 49 | const DEDICATED = 8; 50 | /** 51 | * Generated from protobuf enum TVOS = 9; 52 | */ 53 | const TVOS = 9; 54 | /** 55 | * Generated from protobuf enum PLAYSTATION = 10; 56 | */ 57 | const PLAYSTATION = 10; 58 | /** 59 | * Generated from protobuf enum NINTENDO = 11; 60 | */ 61 | const NINTENDO = 11; 62 | /** 63 | * Generated from protobuf enum XBOX = 12; 64 | */ 65 | const XBOX = 12; 66 | /** 67 | * Generated from protobuf enum WINDOWS_PHONE = 13; 68 | */ 69 | const WINDOWS_PHONE = 13; 70 | 71 | private static $valueToName = [ 72 | self::Android => 'Android', 73 | self::IOS => 'IOS', 74 | self::OSX => 'OSX', 75 | self::AMAZON => 'AMAZON', 76 | self::GEAR_VR => 'GEAR_VR', 77 | self::HOLOLENS => 'HOLOLENS', 78 | self::WINDOWS_10 => 'WINDOWS_10', 79 | self::WIN32 => 'WIN32', 80 | self::DEDICATED => 'DEDICATED', 81 | self::TVOS => 'TVOS', 82 | self::PLAYSTATION => 'PLAYSTATION', 83 | self::NINTENDO => 'NINTENDO', 84 | self::XBOX => 'XBOX', 85 | self::WINDOWS_PHONE => 'WINDOWS_PHONE', 86 | ]; 87 | 88 | public static function name($value) 89 | { 90 | if (!isset(self::$valueToName[$value])) { 91 | throw new UnexpectedValueException(sprintf( 92 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 93 | } 94 | return self::$valueToName[$value]; 95 | } 96 | 97 | 98 | public static function value($name) 99 | { 100 | $const = __CLASS__ . '::' . strtoupper($name); 101 | if (!defined($const)) { 102 | throw new UnexpectedValueException(sprintf( 103 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 104 | } 105 | return constant($const); 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/ItemData.php: -------------------------------------------------------------------------------- 1 | xchange.ItemData 13 | */ 14 | class ItemData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.ItemFeature feature = 1; 18 | */ 19 | protected $feature = null; 20 | /** 21 | * Generated from protobuf field string vanillaName = 2; 22 | */ 23 | protected $vanillaName = ''; 24 | /** 25 | * Generated from protobuf field uint32 count = 3; 26 | */ 27 | protected $count = 0; 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param array $data { 33 | * Optional. Data for populating the Message object. 34 | * 35 | * @type \prokits\xyron\ItemFeature $feature 36 | * @type string $vanillaName 37 | * @type int $count 38 | * } 39 | */ 40 | public function __construct($data = NULL) { 41 | \GPBMetadata\PrimitiveTypes::initOnce(); 42 | parent::__construct($data); 43 | } 44 | 45 | /** 46 | * Generated from protobuf field .xchange.ItemFeature feature = 1; 47 | * @return \prokits\xyron\ItemFeature|null 48 | */ 49 | public function getFeature() 50 | { 51 | return $this->feature; 52 | } 53 | 54 | public function hasFeature() 55 | { 56 | return isset($this->feature); 57 | } 58 | 59 | public function clearFeature() 60 | { 61 | unset($this->feature); 62 | } 63 | 64 | /** 65 | * Generated from protobuf field .xchange.ItemFeature feature = 1; 66 | * @param \prokits\xyron\ItemFeature $var 67 | * @return $this 68 | */ 69 | public function setFeature($var) 70 | { 71 | GPBUtil::checkMessage($var, \prokits\xyron\ItemFeature::class); 72 | $this->feature = $var; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Generated from protobuf field string vanillaName = 2; 79 | * @return string 80 | */ 81 | public function getVanillaName() 82 | { 83 | return $this->vanillaName; 84 | } 85 | 86 | /** 87 | * Generated from protobuf field string vanillaName = 2; 88 | * @param string $var 89 | * @return $this 90 | */ 91 | public function setVanillaName($var) 92 | { 93 | GPBUtil::checkString($var, True); 94 | $this->vanillaName = $var; 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * Generated from protobuf field uint32 count = 3; 101 | * @return int 102 | */ 103 | public function getCount() 104 | { 105 | return $this->count; 106 | } 107 | 108 | /** 109 | * Generated from protobuf field uint32 count = 3; 110 | * @param int $var 111 | * @return $this 112 | */ 113 | public function setCount($var) 114 | { 115 | GPBUtil::checkUint32($var); 116 | $this->count = $var; 117 | 118 | return $this; 119 | } 120 | 121 | } 122 | 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xyron - Minecraft Bedrock Edition Concept Anticheat 2 | 3 | Xyron is a concept anticheat designed for Minecraft Bedrock Edition. It aims to provide a robust solution for detecting 4 | and preventing cheating in Bedrock servers, ensuring fair gameplay and a positive gaming experience for all players. 5 | 6 | ## Project Structure 7 | 8 | The Xyron project is organized into several directories, each serving a specific purpose. Here's an overview of the 9 | project structure: 10 | 11 | ### 1. `anticheat` 12 | 13 | This directory contains the backend server demo, written in Golang. The backend server is responsible for handling 14 | anticheat functionalities and processing player data. It acts as the core component of the Xyron anticheat system. 15 | 16 | ### 2. `implementation` 17 | 18 | Here you can find the anticheat check demo. This section demonstrates how the anticheat mechanisms work in practice, 19 | showcasing various cheat-detection techniques implemented in the concept. This demo allows you to see the anticheat in 20 | action and understand its effectiveness. 21 | 22 | ### 3. `src/main/proto` 23 | 24 | The `src/main/proto` directory contains the protobuf files used for data exchange and communication between different 25 | components of the Xyron anticheat system. These files define the data structures and communication protocols that 26 | facilitate seamless integration and interaction between various parts of the system. 27 | 28 | ### 4. `java_protobuf`, `src/main/php`, `xyron` 29 | 30 | These directories store the generated code for Golang, derived from the protobuf files. The code in these directories is 31 | used to implement specific functionalities of the Xyron anticheat system. The code is automatically generated based on 32 | the defined data structures and communication protocols in the `src/main/proto` directory. 33 | 34 | ### 5. `nukkit_binding` 35 | 36 | Nukkit frontend. 37 | 38 | ### 6. `anticheat_test_binding.go` 39 | 40 | Dragonfly frontend. 41 | 42 | ## Getting Started 43 | 44 | To start using Xyron, follow these steps: 45 | 46 | 1. Clone this repository to your local machine. 47 | 2. Implement a proper backend server (for demonstrate, see `anticheat`). 48 | 3. Integrate the frontend binding into your Minecraft Bedrock server to connect it with the backend anticheat server. 49 | Refer to the documentation or README in the `implementation` directory for guidance. 50 | 4. If you want to understand the data exchange protocols, examine the protobuf files located in the `xchange` directory. 51 | These files define how data is formatted and exchanged between different components of the Xyron anticheat system. 52 | 53 | ## Contributing 54 | 55 | We welcome contributions from the community to improve and expand the capabilities of Xyron. If you'd like to 56 | contribute, please follow these guidelines: 57 | 58 | 1. Fork the repository and create your branch from the `main` branch. 59 | 2. Make your changes, ensuring to maintain a clean and readable codebase. 60 | 3. Test your changes thoroughly, considering various scenarios and edge cases. 61 | 4. Submit a pull request, and our team will review it as soon as possible. 62 | 63 | ## License 64 | 65 | Xyron is licensed under the [MIT License](https://opensource.org/licenses/MIT). You are free to use, modify, and 66 | distribute the code as per the terms of the license. 67 | 68 | ## Contact & Support 69 | 70 | If you have any questions, suggestions, or feedback, you can reach out to us by opening a GitHub issue. We'd love to 71 | hear from you! 72 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/PlayerAction.php: -------------------------------------------------------------------------------- 1 | xchange.PlayerAction 11 | */ 12 | class PlayerAction 13 | { 14 | /** 15 | * Generated from protobuf enum Jump = 0; 16 | */ 17 | const Jump = 0; 18 | /** 19 | * Generated from protobuf enum Swing = 1; 20 | */ 21 | const Swing = 1; 22 | /** 23 | * Generated from protobuf enum StartSprint = 2; 24 | */ 25 | const StartSprint = 2; 26 | /** 27 | * Generated from protobuf enum StopSprint = 3; 28 | */ 29 | const StopSprint = 3; 30 | /** 31 | * Generated from protobuf enum StartSneak = 4; 32 | */ 33 | const StartSneak = 4; 34 | /** 35 | * Generated from protobuf enum StopSneak = 5; 36 | */ 37 | const StopSneak = 5; 38 | /** 39 | * Generated from protobuf enum StartSprintFlying = 6; 40 | */ 41 | const StartSprintFlying = 6; 42 | /** 43 | * Generated from protobuf enum StopSprintFlying = 7; 44 | */ 45 | const StopSprintFlying = 7; 46 | /** 47 | * Generated from protobuf enum StartGliding = 8; 48 | */ 49 | const StartGliding = 8; 50 | /** 51 | * Generated from protobuf enum StopGliding = 9; 52 | */ 53 | const StopGliding = 9; 54 | /** 55 | * Generated from protobuf enum StartSwimming = 10; 56 | */ 57 | const StartSwimming = 10; 58 | /** 59 | * Generated from protobuf enum StopSwimming = 11; 60 | */ 61 | const StopSwimming = 11; 62 | /** 63 | * Generated from protobuf enum OpenInventory = 12; 64 | */ 65 | const OpenInventory = 12; 66 | /** 67 | * Generated from protobuf enum CloseInventory = 13; 68 | */ 69 | const CloseInventory = 13; 70 | 71 | private static $valueToName = [ 72 | self::Jump => 'Jump', 73 | self::Swing => 'Swing', 74 | self::StartSprint => 'StartSprint', 75 | self::StopSprint => 'StopSprint', 76 | self::StartSneak => 'StartSneak', 77 | self::StopSneak => 'StopSneak', 78 | self::StartSprintFlying => 'StartSprintFlying', 79 | self::StopSprintFlying => 'StopSprintFlying', 80 | self::StartGliding => 'StartGliding', 81 | self::StopGliding => 'StopGliding', 82 | self::StartSwimming => 'StartSwimming', 83 | self::StopSwimming => 'StopSwimming', 84 | self::OpenInventory => 'OpenInventory', 85 | self::CloseInventory => 'CloseInventory', 86 | ]; 87 | 88 | public static function name($value) 89 | { 90 | if (!isset(self::$valueToName[$value])) { 91 | throw new UnexpectedValueException(sprintf( 92 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 93 | } 94 | return self::$valueToName[$value]; 95 | } 96 | 97 | 98 | public static function value($name) 99 | { 100 | $const = __CLASS__ . '::' . strtoupper($name); 101 | if (!defined($const)) { 102 | throw new UnexpectedValueException(sprintf( 103 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 104 | } 105 | return constant($const); 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/ReportData.php: -------------------------------------------------------------------------------- 1 | xchange.ReportData 13 | */ 14 | class ReportData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.PlayerReceipt player = 1; 18 | */ 19 | protected $player = null; 20 | /** 21 | * Generated from protobuf field double latency = 2; 22 | */ 23 | protected $latency = 0.0; 24 | /** 25 | *timestamp->report data 26 | * 27 | * Generated from protobuf field map data = 3; 28 | */ 29 | private $data; 30 | 31 | /** 32 | * Constructor. 33 | * 34 | * @param array $data { 35 | * Optional. Data for populating the Message object. 36 | * 37 | * @type \prokits\xyron\PlayerReceipt $player 38 | * @type float $latency 39 | * @type array|\Google\Protobuf\Internal\MapField $data 40 | * timestamp->report data 41 | * } 42 | */ 43 | public function __construct($data = NULL) { 44 | \GPBMetadata\Xchange::initOnce(); 45 | parent::__construct($data); 46 | } 47 | 48 | /** 49 | * Generated from protobuf field .xchange.PlayerReceipt player = 1; 50 | * @return \prokits\xyron\PlayerReceipt|null 51 | */ 52 | public function getPlayer() 53 | { 54 | return $this->player; 55 | } 56 | 57 | public function hasPlayer() 58 | { 59 | return isset($this->player); 60 | } 61 | 62 | public function clearPlayer() 63 | { 64 | unset($this->player); 65 | } 66 | 67 | /** 68 | * Generated from protobuf field .xchange.PlayerReceipt player = 1; 69 | * @param \prokits\xyron\PlayerReceipt $var 70 | * @return $this 71 | */ 72 | public function setPlayer($var) 73 | { 74 | GPBUtil::checkMessage($var, \prokits\xyron\PlayerReceipt::class); 75 | $this->player = $var; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * Generated from protobuf field double latency = 2; 82 | * @return float 83 | */ 84 | public function getLatency() 85 | { 86 | return $this->latency; 87 | } 88 | 89 | /** 90 | * Generated from protobuf field double latency = 2; 91 | * @param float $var 92 | * @return $this 93 | */ 94 | public function setLatency($var) 95 | { 96 | GPBUtil::checkDouble($var); 97 | $this->latency = $var; 98 | 99 | return $this; 100 | } 101 | 102 | /** 103 | *timestamp->report data 104 | * 105 | * Generated from protobuf field map data = 3; 106 | * @return \Google\Protobuf\Internal\MapField 107 | */ 108 | public function getData() 109 | { 110 | return $this->data; 111 | } 112 | 113 | /** 114 | *timestamp->report data 115 | * 116 | * Generated from protobuf field map data = 3; 117 | * @param array|\Google\Protobuf\Internal\MapField $var 118 | * @return $this 119 | */ 120 | public function setData($var) 121 | { 122 | $arr = GPBUtil::checkMapField($var, \Google\Protobuf\Internal\GPBType::INT64, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\TimestampedReportData::class); 123 | $this->data = $arr; 124 | 125 | return $this; 126 | } 127 | 128 | } 129 | 130 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/AttackData.php: -------------------------------------------------------------------------------- 1 | xchange.AttackData 13 | */ 14 | class AttackData extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field .xchange.DamageCause cause = 1; 18 | */ 19 | protected $cause = 0; 20 | /** 21 | * Generated from protobuf field .xchange.EntityPositionData attacker = 2; 22 | */ 23 | protected $attacker = null; 24 | /** 25 | * Generated from protobuf field .xchange.EntityPositionData target = 3; 26 | */ 27 | protected $target = null; 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param array $data { 33 | * Optional. Data for populating the Message object. 34 | * 35 | * @type int $cause 36 | * @type \prokits\xyron\EntityPositionData $attacker 37 | * @type \prokits\xyron\EntityPositionData $target 38 | * } 39 | */ 40 | public function __construct($data = NULL) { 41 | \GPBMetadata\Player::initOnce(); 42 | parent::__construct($data); 43 | } 44 | 45 | /** 46 | * Generated from protobuf field .xchange.DamageCause cause = 1; 47 | * @return int 48 | */ 49 | public function getCause() 50 | { 51 | return $this->cause; 52 | } 53 | 54 | /** 55 | * Generated from protobuf field .xchange.DamageCause cause = 1; 56 | * @param int $var 57 | * @return $this 58 | */ 59 | public function setCause($var) 60 | { 61 | GPBUtil::checkEnum($var, \prokits\xyron\DamageCause::class); 62 | $this->cause = $var; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * Generated from protobuf field .xchange.EntityPositionData attacker = 2; 69 | * @return \prokits\xyron\EntityPositionData|null 70 | */ 71 | public function getAttacker() 72 | { 73 | return $this->attacker; 74 | } 75 | 76 | public function hasAttacker() 77 | { 78 | return isset($this->attacker); 79 | } 80 | 81 | public function clearAttacker() 82 | { 83 | unset($this->attacker); 84 | } 85 | 86 | /** 87 | * Generated from protobuf field .xchange.EntityPositionData attacker = 2; 88 | * @param \prokits\xyron\EntityPositionData $var 89 | * @return $this 90 | */ 91 | public function setAttacker($var) 92 | { 93 | GPBUtil::checkMessage($var, \prokits\xyron\EntityPositionData::class); 94 | $this->attacker = $var; 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * Generated from protobuf field .xchange.EntityPositionData target = 3; 101 | * @return \prokits\xyron\EntityPositionData|null 102 | */ 103 | public function getTarget() 104 | { 105 | return $this->target; 106 | } 107 | 108 | public function hasTarget() 109 | { 110 | return isset($this->target); 111 | } 112 | 113 | public function clearTarget() 114 | { 115 | unset($this->target); 116 | } 117 | 118 | /** 119 | * Generated from protobuf field .xchange.EntityPositionData target = 3; 120 | * @param \prokits\xyron\EntityPositionData $var 121 | * @return $this 122 | */ 123 | public function setTarget($var) 124 | { 125 | GPBUtil::checkMessage($var, \prokits\xyron\EntityPositionData::class); 126 | $this->target = $var; 127 | 128 | return $this; 129 | } 130 | 131 | } 132 | 133 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/DamageCause.php: -------------------------------------------------------------------------------- 1 | xchange.DamageCause 11 | */ 12 | class DamageCause 13 | { 14 | /** 15 | * Generated from protobuf enum Contact = 0; 16 | */ 17 | const Contact = 0; 18 | /** 19 | * Generated from protobuf enum EntityAttack = 1; 20 | */ 21 | const EntityAttack = 1; 22 | /** 23 | * Generated from protobuf enum Projectile = 2; 24 | */ 25 | const Projectile = 2; 26 | /** 27 | * Generated from protobuf enum Suffocation = 3; 28 | */ 29 | const Suffocation = 3; 30 | /** 31 | * Generated from protobuf enum Fall = 4; 32 | */ 33 | const Fall = 4; 34 | /** 35 | * Generated from protobuf enum Fire = 5; 36 | */ 37 | const Fire = 5; 38 | /** 39 | * Generated from protobuf enum FireTick = 6; 40 | */ 41 | const FireTick = 6; 42 | /** 43 | * Generated from protobuf enum Lava = 7; 44 | */ 45 | const Lava = 7; 46 | /** 47 | * Generated from protobuf enum Drowning = 8; 48 | */ 49 | const Drowning = 8; 50 | /** 51 | * Generated from protobuf enum BlockExplosion = 9; 52 | */ 53 | const BlockExplosion = 9; 54 | /** 55 | * Generated from protobuf enum EntityExplosion = 10; 56 | */ 57 | const EntityExplosion = 10; 58 | /** 59 | * Generated from protobuf enum Void = 11; 60 | */ 61 | const Void = 11; 62 | /** 63 | * Generated from protobuf enum Suicide = 12; 64 | */ 65 | const Suicide = 12; 66 | /** 67 | * Generated from protobuf enum Magic = 13; 68 | */ 69 | const Magic = 13; 70 | /** 71 | * Generated from protobuf enum Custom = 14; 72 | */ 73 | const Custom = 14; 74 | /** 75 | * Generated from protobuf enum Starvation = 15; 76 | */ 77 | const Starvation = 15; 78 | /** 79 | * Generated from protobuf enum FallingBlock = 16; 80 | */ 81 | const FallingBlock = 16; 82 | 83 | private static $valueToName = [ 84 | self::Contact => 'Contact', 85 | self::EntityAttack => 'EntityAttack', 86 | self::Projectile => 'Projectile', 87 | self::Suffocation => 'Suffocation', 88 | self::Fall => 'Fall', 89 | self::Fire => 'Fire', 90 | self::FireTick => 'FireTick', 91 | self::Lava => 'Lava', 92 | self::Drowning => 'Drowning', 93 | self::BlockExplosion => 'BlockExplosion', 94 | self::EntityExplosion => 'EntityExplosion', 95 | self::Void => 'Void', 96 | self::Suicide => 'Suicide', 97 | self::Magic => 'Magic', 98 | self::Custom => 'Custom', 99 | self::Starvation => 'Starvation', 100 | self::FallingBlock => 'FallingBlock', 101 | ]; 102 | 103 | public static function name($value) 104 | { 105 | if (!isset(self::$valueToName[$value])) { 106 | throw new UnexpectedValueException(sprintf( 107 | 'Enum %s has no name defined for value %s', __CLASS__, $value)); 108 | } 109 | return self::$valueToName[$value]; 110 | } 111 | 112 | 113 | public static function value($name) 114 | { 115 | $const = __CLASS__ . '::' . strtoupper($name); 116 | if (!defined($const)) { 117 | throw new UnexpectedValueException(sprintf( 118 | 'Enum %s has no value defined for name %s', __CLASS__, $name)); 119 | } 120 | return constant($const); 121 | } 122 | } 123 | 124 | -------------------------------------------------------------------------------- /anticheat/anticheat.go: -------------------------------------------------------------------------------- 1 | package anticheat 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/blackjack200/xyron/xyron" 7 | "github.com/sirupsen/logrus" 8 | "google.golang.org/protobuf/types/known/emptypb" 9 | "sync" 10 | "sync/atomic" 11 | "time" 12 | ) 13 | 14 | type SimpleAnticheat struct { 15 | xyron.AnticheatServer 16 | mu *sync.Mutex 17 | log *logrus.Logger 18 | players map[string]*InternalPlayer 19 | checks func() []any 20 | running atomic.Bool 21 | } 22 | 23 | func NewSimpleAnticheatServer(log *logrus.Logger, checks func() []any) (*SimpleAnticheat, func()) { 24 | s := &SimpleAnticheat{ 25 | mu: &sync.Mutex{}, 26 | log: log, 27 | players: make(map[string]*InternalPlayer), 28 | checks: checks, 29 | running: atomic.Bool{}, 30 | } 31 | s.running.Store(true) 32 | go func() { 33 | t := time.NewTicker(time.Second * 5) 34 | for s.running.Load() { 35 | select { 36 | case _ = <-t.C: 37 | s.mu.Lock() 38 | for id, p := range s.players { 39 | if time.Now().Sub(p.lastReport).Seconds() > 30 { 40 | s.log. 41 | WithField("player", p.Name). 42 | WithField("player_id", id). 43 | Debugf("timeout") 44 | delete(s.players, id) 45 | } 46 | } 47 | s.mu.Unlock() 48 | } 49 | time.Sleep(time.Second) 50 | } 51 | }() 52 | return s, func() { 53 | s.running.Store(false) 54 | } 55 | } 56 | 57 | func (s *SimpleAnticheat) AddPlayer(_ context.Context, req *xyron.AddPlayerRequest) (*xyron.PlayerReceipt, error) { 58 | s.mu.Lock() 59 | defer s.mu.Unlock() 60 | 61 | id := internalId(req.Player.Name) 62 | 63 | if _, ok := s.players[id]; ok { 64 | return nil, fmt.Errorf("player already exists: %v", id) 65 | } 66 | 67 | p := NewInternalPlayer(s.log, s.checks(), req.Player.Os, req.Player.Name) 68 | s.players[id] = p 69 | s.handleData(p, req.Data) 70 | 71 | s.log. 72 | WithField("player", req.Player.Name). 73 | WithField("player_id", id). 74 | Infof("add") 75 | 76 | return &xyron.PlayerReceipt{InternalId: id}, nil 77 | } 78 | 79 | func (s *SimpleAnticheat) RemovePlayer(_ context.Context, r *xyron.PlayerReceipt) (*emptypb.Empty, error) { 80 | s.mu.Lock() 81 | s.log. 82 | WithField("player_id", r.InternalId). 83 | Infof("remove") 84 | delete(s.players, r.InternalId) 85 | s.mu.Unlock() 86 | return &emptypb.Empty{}, nil 87 | } 88 | 89 | func (s *SimpleAnticheat) Report(_ context.Context, r *xyron.ReportData) (*xyron.ReportResponse, error) { 90 | var p *InternalPlayer 91 | s.mu.Lock() 92 | if pp, ok := s.players[r.Player.GetInternalId()]; !ok { 93 | return nil, fmt.Errorf("player %v not found", r.Player.InternalId) 94 | } else { 95 | p = pp 96 | } 97 | s.mu.Unlock() 98 | //log.Printf("RP:%v", r.Player.InternalId) 99 | jdjm := s.handleData(p, r.Data) 100 | return &xyron.ReportResponse{Judgements: jdjm}, nil 101 | } 102 | 103 | func (s *SimpleAnticheat) ReportBatched(_ context.Context, data *xyron.BatchedReportData) (*xyron.BatchedReportResponse, error) { 104 | f := func(d *xyron.ReportData) *xyron.BatchedReportResponseEntry { 105 | s.mu.Lock() 106 | var p *InternalPlayer 107 | if pp, ok := s.players[d.Player.GetInternalId()]; !ok { 108 | return nil 109 | } else { 110 | p = pp 111 | } 112 | s.mu.Unlock() 113 | //log.Printf("RP:%v", r.Player.InternalId) 114 | jdjm := s.handleData(p, d.Data) 115 | return &xyron.BatchedReportResponseEntry{ 116 | Player: d.Player, 117 | Judgements: jdjm, 118 | } 119 | } 120 | wg := sync.WaitGroup{} 121 | mu := &sync.Mutex{} 122 | var res []*xyron.BatchedReportResponseEntry 123 | for _, d := range data.Data { 124 | d := d 125 | wg.Add(1) 126 | go func() { 127 | resp := f(d) 128 | if resp != nil { 129 | mu.Lock() 130 | res = append(res, resp) 131 | mu.Unlock() 132 | } 133 | wg.Done() 134 | }() 135 | } 136 | wg.Wait() 137 | return &xyron.BatchedReportResponse{Data: nil}, nil 138 | } 139 | -------------------------------------------------------------------------------- /xyron/anticheat_types.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.1 4 | // protoc v4.23.1 5 | // source: anticheat_types.proto 6 | 7 | package xyron 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type Judgement int32 24 | 25 | const ( 26 | Judgement_DEBUG Judgement = 0 27 | Judgement_AMBIGUOUS Judgement = 1 28 | Judgement_TRIGGER Judgement = 2 29 | ) 30 | 31 | // Enum value maps for Judgement. 32 | var ( 33 | Judgement_name = map[int32]string{ 34 | 0: "DEBUG", 35 | 1: "AMBIGUOUS", 36 | 2: "TRIGGER", 37 | } 38 | Judgement_value = map[string]int32{ 39 | "DEBUG": 0, 40 | "AMBIGUOUS": 1, 41 | "TRIGGER": 2, 42 | } 43 | ) 44 | 45 | func (x Judgement) Enum() *Judgement { 46 | p := new(Judgement) 47 | *p = x 48 | return p 49 | } 50 | 51 | func (x Judgement) String() string { 52 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 53 | } 54 | 55 | func (Judgement) Descriptor() protoreflect.EnumDescriptor { 56 | return file_anticheat_types_proto_enumTypes[0].Descriptor() 57 | } 58 | 59 | func (Judgement) Type() protoreflect.EnumType { 60 | return &file_anticheat_types_proto_enumTypes[0] 61 | } 62 | 63 | func (x Judgement) Number() protoreflect.EnumNumber { 64 | return protoreflect.EnumNumber(x) 65 | } 66 | 67 | // Deprecated: Use Judgement.Descriptor instead. 68 | func (Judgement) EnumDescriptor() ([]byte, []int) { 69 | return file_anticheat_types_proto_rawDescGZIP(), []int{0} 70 | } 71 | 72 | var File_anticheat_types_proto protoreflect.FileDescriptor 73 | 74 | var file_anticheat_types_proto_rawDesc = []byte{ 75 | 0x0a, 0x15, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x68, 0x65, 0x61, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 76 | 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 77 | 0x2a, 0x32, 0x0a, 0x09, 0x4a, 0x75, 0x64, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x09, 0x0a, 78 | 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x4d, 0x42, 0x49, 79 | 0x47, 0x55, 0x4f, 0x55, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x54, 0x52, 0x49, 0x47, 0x47, 80 | 0x45, 0x52, 0x10, 0x02, 0x42, 0x3d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x69, 0x74, 0x68, 81 | 0x75, 0x62, 0x2e, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x6a, 0x61, 0x63, 0x6b, 0x32, 0x30, 0x30, 0x2e, 82 | 0x78, 0x79, 0x72, 0x6f, 0x6e, 0x5a, 0x06, 0x78, 0x79, 0x72, 0x6f, 0x6e, 0x2f, 0x88, 0x01, 0x01, 83 | 0xca, 0x02, 0x0d, 0x70, 0x72, 0x6f, 0x6b, 0x69, 0x74, 0x73, 0x5c, 0x78, 0x79, 0x72, 0x6f, 0x6e, 84 | 0xd0, 0x02, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 85 | } 86 | 87 | var ( 88 | file_anticheat_types_proto_rawDescOnce sync.Once 89 | file_anticheat_types_proto_rawDescData = file_anticheat_types_proto_rawDesc 90 | ) 91 | 92 | func file_anticheat_types_proto_rawDescGZIP() []byte { 93 | file_anticheat_types_proto_rawDescOnce.Do(func() { 94 | file_anticheat_types_proto_rawDescData = protoimpl.X.CompressGZIP(file_anticheat_types_proto_rawDescData) 95 | }) 96 | return file_anticheat_types_proto_rawDescData 97 | } 98 | 99 | var file_anticheat_types_proto_enumTypes = make([]protoimpl.EnumInfo, 1) 100 | var file_anticheat_types_proto_goTypes = []interface{}{ 101 | (Judgement)(0), // 0: xchange.Judgement 102 | } 103 | var file_anticheat_types_proto_depIdxs = []int32{ 104 | 0, // [0:0] is the sub-list for method output_type 105 | 0, // [0:0] is the sub-list for method input_type 106 | 0, // [0:0] is the sub-list for extension type_name 107 | 0, // [0:0] is the sub-list for extension extendee 108 | 0, // [0:0] is the sub-list for field type_name 109 | } 110 | 111 | func init() { file_anticheat_types_proto_init() } 112 | func file_anticheat_types_proto_init() { 113 | if File_anticheat_types_proto != nil { 114 | return 115 | } 116 | type x struct{} 117 | out := protoimpl.TypeBuilder{ 118 | File: protoimpl.DescBuilder{ 119 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 120 | RawDescriptor: file_anticheat_types_proto_rawDesc, 121 | NumEnums: 1, 122 | NumMessages: 0, 123 | NumExtensions: 0, 124 | NumServices: 0, 125 | }, 126 | GoTypes: file_anticheat_types_proto_goTypes, 127 | DependencyIndexes: file_anticheat_types_proto_depIdxs, 128 | EnumInfos: file_anticheat_types_proto_enumTypes, 129 | }.Build() 130 | File_anticheat_types_proto = out.File 131 | file_anticheat_types_proto_rawDesc = nil 132 | file_anticheat_types_proto_goTypes = nil 133 | file_anticheat_types_proto_depIdxs = nil 134 | } 135 | -------------------------------------------------------------------------------- /java_protobuf/src/main/java/com/github/blackjack200/xyron/AnticheatTypes.java: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: anticheat_types.proto 3 | 4 | package com.github.blackjack200.xyron; 5 | 6 | public final class AnticheatTypes { 7 | private AnticheatTypes() {} 8 | public static void registerAllExtensions( 9 | com.google.protobuf.ExtensionRegistryLite registry) { 10 | } 11 | 12 | public static void registerAllExtensions( 13 | com.google.protobuf.ExtensionRegistry registry) { 14 | registerAllExtensions( 15 | (com.google.protobuf.ExtensionRegistryLite) registry); 16 | } 17 | /** 18 | * Protobuf enum {@code xchange.Judgement} 19 | */ 20 | public enum Judgement 21 | implements com.google.protobuf.ProtocolMessageEnum { 22 | /** 23 | * DEBUG = 0; 24 | */ 25 | DEBUG(0), 26 | /** 27 | * AMBIGUOUS = 1; 28 | */ 29 | AMBIGUOUS(1), 30 | /** 31 | * TRIGGER = 2; 32 | */ 33 | TRIGGER(2), 34 | UNRECOGNIZED(-1), 35 | ; 36 | 37 | /** 38 | * DEBUG = 0; 39 | */ 40 | public static final int DEBUG_VALUE = 0; 41 | /** 42 | * AMBIGUOUS = 1; 43 | */ 44 | public static final int AMBIGUOUS_VALUE = 1; 45 | /** 46 | * TRIGGER = 2; 47 | */ 48 | public static final int TRIGGER_VALUE = 2; 49 | 50 | 51 | public final int getNumber() { 52 | if (this == UNRECOGNIZED) { 53 | throw new java.lang.IllegalArgumentException( 54 | "Can't get the number of an unknown enum value."); 55 | } 56 | return value; 57 | } 58 | 59 | /** 60 | * @param value The numeric wire value of the corresponding enum entry. 61 | * @return The enum associated with the given numeric wire value. 62 | * @deprecated Use {@link #forNumber(int)} instead. 63 | */ 64 | @java.lang.Deprecated 65 | public static Judgement valueOf(int value) { 66 | return forNumber(value); 67 | } 68 | 69 | /** 70 | * @param value The numeric wire value of the corresponding enum entry. 71 | * @return The enum associated with the given numeric wire value. 72 | */ 73 | public static Judgement forNumber(int value) { 74 | switch (value) { 75 | case 0: return DEBUG; 76 | case 1: return AMBIGUOUS; 77 | case 2: return TRIGGER; 78 | default: return null; 79 | } 80 | } 81 | 82 | public static com.google.protobuf.Internal.EnumLiteMap 83 | internalGetValueMap() { 84 | return internalValueMap; 85 | } 86 | private static final com.google.protobuf.Internal.EnumLiteMap< 87 | Judgement> internalValueMap = 88 | new com.google.protobuf.Internal.EnumLiteMap() { 89 | public Judgement findValueByNumber(int number) { 90 | return Judgement.forNumber(number); 91 | } 92 | }; 93 | 94 | public final com.google.protobuf.Descriptors.EnumValueDescriptor 95 | getValueDescriptor() { 96 | if (this == UNRECOGNIZED) { 97 | throw new java.lang.IllegalStateException( 98 | "Can't get the descriptor of an unrecognized enum value."); 99 | } 100 | return getDescriptor().getValues().get(ordinal()); 101 | } 102 | public final com.google.protobuf.Descriptors.EnumDescriptor 103 | getDescriptorForType() { 104 | return getDescriptor(); 105 | } 106 | public static final com.google.protobuf.Descriptors.EnumDescriptor 107 | getDescriptor() { 108 | return com.github.blackjack200.xyron.AnticheatTypes.getDescriptor().getEnumTypes().get(0); 109 | } 110 | 111 | private static final Judgement[] VALUES = values(); 112 | 113 | public static Judgement valueOf( 114 | com.google.protobuf.Descriptors.EnumValueDescriptor desc) { 115 | if (desc.getType() != getDescriptor()) { 116 | throw new java.lang.IllegalArgumentException( 117 | "EnumValueDescriptor is not for this type."); 118 | } 119 | if (desc.getIndex() == -1) { 120 | return UNRECOGNIZED; 121 | } 122 | return VALUES[desc.getIndex()]; 123 | } 124 | 125 | private final int value; 126 | 127 | private Judgement(int value) { 128 | this.value = value; 129 | } 130 | 131 | // @@protoc_insertion_point(enum_scope:xchange.Judgement) 132 | } 133 | 134 | 135 | public static com.google.protobuf.Descriptors.FileDescriptor 136 | getDescriptor() { 137 | return descriptor; 138 | } 139 | private static com.google.protobuf.Descriptors.FileDescriptor 140 | descriptor; 141 | static { 142 | java.lang.String[] descriptorData = { 143 | "\n\025anticheat_types.proto\022\007xchange*2\n\tJudg" + 144 | "ement\022\t\n\005DEBUG\020\000\022\r\n\tAMBIGUOUS\020\001\022\013\n\007TRIGG" + 145 | "ER\020\002B=\n\035com.github.blackjack200.xyronZ\006x" + 146 | "yron/\210\001\001\312\002\rprokits\\xyron\320\002\001b\006proto3" 147 | }; 148 | descriptor = com.google.protobuf.Descriptors.FileDescriptor 149 | .internalBuildGeneratedFileFrom(descriptorData, 150 | new com.google.protobuf.Descriptors.FileDescriptor[] { 151 | }); 152 | } 153 | 154 | // @@protoc_insertion_point(outer_class_scope) 155 | } 156 | -------------------------------------------------------------------------------- /pmmp_binding/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "5c5f64d67e4db75d37cfe0c533bc6d11", 8 | "packages": [ 9 | { 10 | "name": "blackjack200/xyron", 11 | "version": "dev-master", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/Blackjack200/Xyron.git", 15 | "reference": "c4df2e008562824b4bd2b4a365dfc630d1a4489d" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/Blackjack200/Xyron/zipball/c4df2e008562824b4bd2b4a365dfc630d1a4489d", 20 | "reference": "c4df2e008562824b4bd2b4a365dfc630d1a4489d", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "ext-grpc": "*", 25 | "google/protobuf": "^3.23.4", 26 | "grpc/grpc": "^1.52.0" 27 | }, 28 | "default-branch": true, 29 | "type": "library", 30 | "autoload": { 31 | "psr-4": { 32 | "": [ 33 | "src/main/php" 34 | ] 35 | } 36 | }, 37 | "notification-url": "https://packagist.org/downloads/", 38 | "license": [ 39 | "MIT" 40 | ], 41 | "authors": [ 42 | { 43 | "name": "Blackjack200", 44 | "email": "lx826444126@gmail.com" 45 | } 46 | ], 47 | "support": { 48 | "issues": "https://github.com/Blackjack200/Xyron/issues", 49 | "source": "https://github.com/Blackjack200/Xyron/tree/master" 50 | }, 51 | "time": "2023-07-28T14:46:33+00:00" 52 | }, 53 | { 54 | "name": "google/protobuf", 55 | "version": "v3.23.4", 56 | "source": { 57 | "type": "git", 58 | "url": "https://github.com/protocolbuffers/protobuf-php.git", 59 | "reference": "fa784054760eec532fe8dd1919d3a0a11f5cef1f" 60 | }, 61 | "dist": { 62 | "type": "zip", 63 | "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/fa784054760eec532fe8dd1919d3a0a11f5cef1f", 64 | "reference": "fa784054760eec532fe8dd1919d3a0a11f5cef1f", 65 | "shasum": "" 66 | }, 67 | "require": { 68 | "php": ">=7.0.0" 69 | }, 70 | "require-dev": { 71 | "phpunit/phpunit": ">=5.0.0" 72 | }, 73 | "suggest": { 74 | "ext-bcmath": "Need to support JSON deserialization" 75 | }, 76 | "type": "library", 77 | "autoload": { 78 | "psr-4": { 79 | "Google\\Protobuf\\": "src/Google/Protobuf", 80 | "GPBMetadata\\Google\\Protobuf\\": "src/GPBMetadata/Google/Protobuf" 81 | } 82 | }, 83 | "notification-url": "https://packagist.org/downloads/", 84 | "license": [ 85 | "BSD-3-Clause" 86 | ], 87 | "description": "proto library for PHP", 88 | "homepage": "https://developers.google.com/protocol-buffers/", 89 | "keywords": [ 90 | "proto" 91 | ], 92 | "support": { 93 | "source": "https://github.com/protocolbuffers/protobuf-php/tree/v3.23.4" 94 | }, 95 | "time": "2023-07-06T18:51:48+00:00" 96 | }, 97 | { 98 | "name": "grpc/grpc", 99 | "version": "1.52.0", 100 | "source": { 101 | "type": "git", 102 | "url": "https://github.com/grpc/grpc-php.git", 103 | "reference": "98394cd601a587ca68294e6209bd713856969105" 104 | }, 105 | "dist": { 106 | "type": "zip", 107 | "url": "https://api.github.com/repos/grpc/grpc-php/zipball/98394cd601a587ca68294e6209bd713856969105", 108 | "reference": "98394cd601a587ca68294e6209bd713856969105", 109 | "shasum": "" 110 | }, 111 | "require": { 112 | "php": ">=7.0.0" 113 | }, 114 | "require-dev": { 115 | "google/auth": "^v1.3.0" 116 | }, 117 | "suggest": { 118 | "ext-protobuf": "For better performance, install the protobuf C extension.", 119 | "google/protobuf": "To get started using grpc quickly, install the native protobuf library." 120 | }, 121 | "type": "library", 122 | "autoload": { 123 | "psr-4": { 124 | "Grpc\\": "src/lib/" 125 | } 126 | }, 127 | "notification-url": "https://packagist.org/downloads/", 128 | "license": [ 129 | "Apache-2.0" 130 | ], 131 | "description": "gRPC library for PHP", 132 | "homepage": "https://grpc.io", 133 | "keywords": [ 134 | "rpc" 135 | ], 136 | "support": { 137 | "source": "https://github.com/grpc/grpc-php/tree/v1.52.0" 138 | }, 139 | "time": "2023-02-25T05:20:08+00:00" 140 | } 141 | ], 142 | "packages-dev": [], 143 | "aliases": [], 144 | "minimum-stability": "stable", 145 | "stability-flags": { 146 | "blackjack200/xyron": 20 147 | }, 148 | "prefer-stable": false, 149 | "prefer-lowest": false, 150 | "platform": [], 151 | "platform-dev": [], 152 | "plugin-api-version": "2.3.0" 153 | } 154 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/EffectFeature.php: -------------------------------------------------------------------------------- 1 | xchange.EffectFeature 13 | */ 14 | class EffectFeature extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field int32 amplifier = 1; 18 | */ 19 | protected $amplifier = 0; 20 | /** 21 | * Generated from protobuf field bool isSpeed = 2; 22 | */ 23 | protected $isSpeed = false; 24 | /** 25 | * Generated from protobuf field bool isHaste = 3; 26 | */ 27 | protected $isHaste = false; 28 | /** 29 | * Generated from protobuf field bool isSlowFalling = 4; 30 | */ 31 | protected $isSlowFalling = false; 32 | /** 33 | * Generated from protobuf field bool isLevitation = 5; 34 | */ 35 | protected $isLevitation = false; 36 | /** 37 | * Generated from protobuf field bool isSlowness = 6; 38 | */ 39 | protected $isSlowness = false; 40 | /** 41 | * Generated from protobuf field bool isJumpBoost = 7; 42 | */ 43 | protected $isJumpBoost = false; 44 | 45 | /** 46 | * Constructor. 47 | * 48 | * @param array $data { 49 | * Optional. Data for populating the Message object. 50 | * 51 | * @type int $amplifier 52 | * @type bool $isSpeed 53 | * @type bool $isHaste 54 | * @type bool $isSlowFalling 55 | * @type bool $isLevitation 56 | * @type bool $isSlowness 57 | * @type bool $isJumpBoost 58 | * } 59 | */ 60 | public function __construct($data = NULL) { 61 | \GPBMetadata\PrimitiveTypes::initOnce(); 62 | parent::__construct($data); 63 | } 64 | 65 | /** 66 | * Generated from protobuf field int32 amplifier = 1; 67 | * @return int 68 | */ 69 | public function getAmplifier() 70 | { 71 | return $this->amplifier; 72 | } 73 | 74 | /** 75 | * Generated from protobuf field int32 amplifier = 1; 76 | * @param int $var 77 | * @return $this 78 | */ 79 | public function setAmplifier($var) 80 | { 81 | GPBUtil::checkInt32($var); 82 | $this->amplifier = $var; 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * Generated from protobuf field bool isSpeed = 2; 89 | * @return bool 90 | */ 91 | public function getIsSpeed() 92 | { 93 | return $this->isSpeed; 94 | } 95 | 96 | /** 97 | * Generated from protobuf field bool isSpeed = 2; 98 | * @param bool $var 99 | * @return $this 100 | */ 101 | public function setIsSpeed($var) 102 | { 103 | GPBUtil::checkBool($var); 104 | $this->isSpeed = $var; 105 | 106 | return $this; 107 | } 108 | 109 | /** 110 | * Generated from protobuf field bool isHaste = 3; 111 | * @return bool 112 | */ 113 | public function getIsHaste() 114 | { 115 | return $this->isHaste; 116 | } 117 | 118 | /** 119 | * Generated from protobuf field bool isHaste = 3; 120 | * @param bool $var 121 | * @return $this 122 | */ 123 | public function setIsHaste($var) 124 | { 125 | GPBUtil::checkBool($var); 126 | $this->isHaste = $var; 127 | 128 | return $this; 129 | } 130 | 131 | /** 132 | * Generated from protobuf field bool isSlowFalling = 4; 133 | * @return bool 134 | */ 135 | public function getIsSlowFalling() 136 | { 137 | return $this->isSlowFalling; 138 | } 139 | 140 | /** 141 | * Generated from protobuf field bool isSlowFalling = 4; 142 | * @param bool $var 143 | * @return $this 144 | */ 145 | public function setIsSlowFalling($var) 146 | { 147 | GPBUtil::checkBool($var); 148 | $this->isSlowFalling = $var; 149 | 150 | return $this; 151 | } 152 | 153 | /** 154 | * Generated from protobuf field bool isLevitation = 5; 155 | * @return bool 156 | */ 157 | public function getIsLevitation() 158 | { 159 | return $this->isLevitation; 160 | } 161 | 162 | /** 163 | * Generated from protobuf field bool isLevitation = 5; 164 | * @param bool $var 165 | * @return $this 166 | */ 167 | public function setIsLevitation($var) 168 | { 169 | GPBUtil::checkBool($var); 170 | $this->isLevitation = $var; 171 | 172 | return $this; 173 | } 174 | 175 | /** 176 | * Generated from protobuf field bool isSlowness = 6; 177 | * @return bool 178 | */ 179 | public function getIsSlowness() 180 | { 181 | return $this->isSlowness; 182 | } 183 | 184 | /** 185 | * Generated from protobuf field bool isSlowness = 6; 186 | * @param bool $var 187 | * @return $this 188 | */ 189 | public function setIsSlowness($var) 190 | { 191 | GPBUtil::checkBool($var); 192 | $this->isSlowness = $var; 193 | 194 | return $this; 195 | } 196 | 197 | /** 198 | * Generated from protobuf field bool isJumpBoost = 7; 199 | * @return bool 200 | */ 201 | public function getIsJumpBoost() 202 | { 203 | return $this->isJumpBoost; 204 | } 205 | 206 | /** 207 | * Generated from protobuf field bool isJumpBoost = 7; 208 | * @param bool $var 209 | * @return $this 210 | */ 211 | public function setIsJumpBoost($var) 212 | { 213 | GPBUtil::checkBool($var); 214 | $this->isJumpBoost = $var; 215 | 216 | return $this; 217 | } 218 | 219 | } 220 | 221 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/ItemFeature.php: -------------------------------------------------------------------------------- 1 | xchange.ItemFeature 13 | */ 14 | class ItemFeature extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field bool isArmor = 1; 18 | */ 19 | protected $isArmor = false; 20 | /** 21 | * Generated from protobuf field bool isBlockPlanterItem = 2; 22 | */ 23 | protected $isBlockPlanterItem = false; 24 | /** 25 | * Generated from protobuf field bool isDamageable = 3; 26 | */ 27 | protected $isDamageable = false; 28 | /** 29 | * Generated from protobuf field bool isFood = 4; 30 | */ 31 | protected $isFood = false; 32 | /** 33 | * Generated from protobuf field bool isThrowable = 5; 34 | */ 35 | protected $isThrowable = false; 36 | /** 37 | * Generated from protobuf field bool isTool = 6; 38 | */ 39 | protected $isTool = false; 40 | /** 41 | * Generated from protobuf field bool isBow = 7; 42 | */ 43 | protected $isBow = false; 44 | /** 45 | * Generated from protobuf field bool isCrossBow = 8; 46 | */ 47 | protected $isCrossBow = false; 48 | /** 49 | * Generated from protobuf field bool isShield = 9; 50 | */ 51 | protected $isShield = false; 52 | 53 | /** 54 | * Constructor. 55 | * 56 | * @param array $data { 57 | * Optional. Data for populating the Message object. 58 | * 59 | * @type bool $isArmor 60 | * @type bool $isBlockPlanterItem 61 | * @type bool $isDamageable 62 | * @type bool $isFood 63 | * @type bool $isThrowable 64 | * @type bool $isTool 65 | * @type bool $isBow 66 | * @type bool $isCrossBow 67 | * @type bool $isShield 68 | * } 69 | */ 70 | public function __construct($data = NULL) { 71 | \GPBMetadata\PrimitiveTypes::initOnce(); 72 | parent::__construct($data); 73 | } 74 | 75 | /** 76 | * Generated from protobuf field bool isArmor = 1; 77 | * @return bool 78 | */ 79 | public function getIsArmor() 80 | { 81 | return $this->isArmor; 82 | } 83 | 84 | /** 85 | * Generated from protobuf field bool isArmor = 1; 86 | * @param bool $var 87 | * @return $this 88 | */ 89 | public function setIsArmor($var) 90 | { 91 | GPBUtil::checkBool($var); 92 | $this->isArmor = $var; 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Generated from protobuf field bool isBlockPlanterItem = 2; 99 | * @return bool 100 | */ 101 | public function getIsBlockPlanterItem() 102 | { 103 | return $this->isBlockPlanterItem; 104 | } 105 | 106 | /** 107 | * Generated from protobuf field bool isBlockPlanterItem = 2; 108 | * @param bool $var 109 | * @return $this 110 | */ 111 | public function setIsBlockPlanterItem($var) 112 | { 113 | GPBUtil::checkBool($var); 114 | $this->isBlockPlanterItem = $var; 115 | 116 | return $this; 117 | } 118 | 119 | /** 120 | * Generated from protobuf field bool isDamageable = 3; 121 | * @return bool 122 | */ 123 | public function getIsDamageable() 124 | { 125 | return $this->isDamageable; 126 | } 127 | 128 | /** 129 | * Generated from protobuf field bool isDamageable = 3; 130 | * @param bool $var 131 | * @return $this 132 | */ 133 | public function setIsDamageable($var) 134 | { 135 | GPBUtil::checkBool($var); 136 | $this->isDamageable = $var; 137 | 138 | return $this; 139 | } 140 | 141 | /** 142 | * Generated from protobuf field bool isFood = 4; 143 | * @return bool 144 | */ 145 | public function getIsFood() 146 | { 147 | return $this->isFood; 148 | } 149 | 150 | /** 151 | * Generated from protobuf field bool isFood = 4; 152 | * @param bool $var 153 | * @return $this 154 | */ 155 | public function setIsFood($var) 156 | { 157 | GPBUtil::checkBool($var); 158 | $this->isFood = $var; 159 | 160 | return $this; 161 | } 162 | 163 | /** 164 | * Generated from protobuf field bool isThrowable = 5; 165 | * @return bool 166 | */ 167 | public function getIsThrowable() 168 | { 169 | return $this->isThrowable; 170 | } 171 | 172 | /** 173 | * Generated from protobuf field bool isThrowable = 5; 174 | * @param bool $var 175 | * @return $this 176 | */ 177 | public function setIsThrowable($var) 178 | { 179 | GPBUtil::checkBool($var); 180 | $this->isThrowable = $var; 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * Generated from protobuf field bool isTool = 6; 187 | * @return bool 188 | */ 189 | public function getIsTool() 190 | { 191 | return $this->isTool; 192 | } 193 | 194 | /** 195 | * Generated from protobuf field bool isTool = 6; 196 | * @param bool $var 197 | * @return $this 198 | */ 199 | public function setIsTool($var) 200 | { 201 | GPBUtil::checkBool($var); 202 | $this->isTool = $var; 203 | 204 | return $this; 205 | } 206 | 207 | /** 208 | * Generated from protobuf field bool isBow = 7; 209 | * @return bool 210 | */ 211 | public function getIsBow() 212 | { 213 | return $this->isBow; 214 | } 215 | 216 | /** 217 | * Generated from protobuf field bool isBow = 7; 218 | * @param bool $var 219 | * @return $this 220 | */ 221 | public function setIsBow($var) 222 | { 223 | GPBUtil::checkBool($var); 224 | $this->isBow = $var; 225 | 226 | return $this; 227 | } 228 | 229 | /** 230 | * Generated from protobuf field bool isCrossBow = 8; 231 | * @return bool 232 | */ 233 | public function getIsCrossBow() 234 | { 235 | return $this->isCrossBow; 236 | } 237 | 238 | /** 239 | * Generated from protobuf field bool isCrossBow = 8; 240 | * @param bool $var 241 | * @return $this 242 | */ 243 | public function setIsCrossBow($var) 244 | { 245 | GPBUtil::checkBool($var); 246 | $this->isCrossBow = $var; 247 | 248 | return $this; 249 | } 250 | 251 | /** 252 | * Generated from protobuf field bool isShield = 9; 253 | * @return bool 254 | */ 255 | public function getIsShield() 256 | { 257 | return $this->isShield; 258 | } 259 | 260 | /** 261 | * Generated from protobuf field bool isShield = 9; 262 | * @param bool $var 263 | * @return $this 264 | */ 265 | public function setIsShield($var) 266 | { 267 | GPBUtil::checkBool($var); 268 | $this->isShield = $var; 269 | 270 | return $this; 271 | } 272 | 273 | } 274 | 275 | -------------------------------------------------------------------------------- /anticheat/player.go: -------------------------------------------------------------------------------- 1 | package anticheat 2 | 3 | import ( 4 | "github.com/blackjack200/xyron/xyron" 5 | "github.com/go-gl/mathgl/mgl64" 6 | "github.com/sirupsen/logrus" 7 | "time" 8 | ) 9 | 10 | type InternalPlayer struct { 11 | log *logrus.Logger 12 | lastReport time.Time 13 | timestampThisTick int64 14 | checks []any 15 | 16 | Name string 17 | 18 | Os xyron.DeviceOS 19 | Input xyron.InputMode 20 | GameMode xyron.GameMode 21 | 22 | Alive *BufferedTimestampedData[bool] 23 | 24 | effects []*xyron.EffectFeature 25 | 26 | Location *BufferedData[*xyron.EntityPositionData] 27 | DeltaPosition *BufferedData[mgl64.Vec3] 28 | 29 | HeldItem *BufferedTimestampedData[*xyron.ItemData] 30 | 31 | Attack *BufferedTimestampedData[*xyron.AttackData] 32 | Jump *BufferedTimestampedData[float64] 33 | Eat *BufferedTimestampedData[bool] 34 | Teleport *BufferedTimestampedData[mgl64.Vec3] 35 | 36 | Motion *BufferedTimestampedData[mgl64.Vec3] 37 | MotionCoolDown int64 38 | 39 | OpenInventory *BufferedTimestampedData[bool] 40 | CloseInventory *BufferedTimestampedData[bool] 41 | 42 | PlaceBlock *BufferedTimestampedData[*xyron.PlayerPlaceBlockData] 43 | BreakBlock *BufferedTimestampedData[*xyron.PlayerBreakBlockData] 44 | 45 | Sprinting *BufferedTimestampedData[bool] 46 | Sneaking *BufferedTimestampedData[bool] 47 | Gliding *BufferedTimestampedData[bool] 48 | Swimming *BufferedTimestampedData[bool] 49 | Flying *BufferedTimestampedData[bool] 50 | 51 | OnGround *BufferedTimestampedData[bool] 52 | OnIce *BufferedTimestampedData[bool] 53 | OnClimbable *BufferedTimestampedData[bool] 54 | InCobweb *BufferedTimestampedData[bool] 55 | InSweetBerry *BufferedTimestampedData[bool] 56 | 57 | IntersectedLiquid *BufferedTimestampedData[bool] 58 | IntersectedSolid *BufferedTimestampedData[bool] 59 | 60 | InAirTick uint32 61 | OnGroundTick uint32 62 | OnIceTick uint32 63 | } 64 | 65 | func NewInternalPlayer(log *logrus.Logger, checks []any, os xyron.DeviceOS, name string) *InternalPlayer { 66 | return &InternalPlayer{ 67 | log: log, 68 | lastReport: time.Now(), 69 | timestampThisTick: 0, 70 | checks: checks, 71 | Name: name, 72 | Os: os, 73 | Input: 0, 74 | GameMode: 0, 75 | Alive: NewBufferedTimestampedData(true), 76 | effects: nil, 77 | Location: NewBufferedData((*xyron.EntityPositionData)(nil)), 78 | DeltaPosition: NewBufferedData(mgl64.Vec3{}), 79 | HeldItem: NewBufferedTimestampedData((*xyron.ItemData)(nil)), 80 | Attack: NewBufferedTimestampedData((*xyron.AttackData)(nil)), 81 | Jump: NewBufferedTimestampedData(float64(0)), 82 | Eat: NewBufferedTimestampedData(false), 83 | Teleport: NewBufferedTimestampedData(mgl64.Vec3{}), 84 | Motion: NewBufferedTimestampedData(mgl64.Vec3{}), 85 | MotionCoolDown: 0, 86 | OpenInventory: NewBufferedTimestampedData(false), 87 | CloseInventory: NewBufferedTimestampedData(false), 88 | PlaceBlock: NewBufferedTimestampedData((*xyron.PlayerPlaceBlockData)(nil)), 89 | BreakBlock: NewBufferedTimestampedData((*xyron.PlayerBreakBlockData)(nil)), 90 | Sprinting: NewBufferedTimestampedData(false), 91 | Sneaking: NewBufferedTimestampedData(false), 92 | Gliding: NewBufferedTimestampedData(false), 93 | Swimming: NewBufferedTimestampedData(false), 94 | Flying: NewBufferedTimestampedData(false), 95 | OnGround: NewBufferedTimestampedData(true), 96 | OnIce: NewBufferedTimestampedData(false), 97 | OnClimbable: NewBufferedTimestampedData(false), 98 | InCobweb: NewBufferedTimestampedData(false), 99 | InSweetBerry: NewBufferedTimestampedData(false), 100 | IntersectedLiquid: NewBufferedTimestampedData(false), 101 | IntersectedSolid: NewBufferedTimestampedData(false), 102 | InAirTick: 0, 103 | OnGroundTick: 0, 104 | OnIceTick: 0, 105 | } 106 | } 107 | 108 | func (p *InternalPlayer) SetLocation(pos *xyron.EntityPositionData) { 109 | p.Location.Set(pos) 110 | if p.Location.Previous() != nil { 111 | prev := toVec3(p.Location.Previous().Position) 112 | cur := toVec3(pos.Position) 113 | p.DeltaPosition.Set(cur.Sub(prev)) 114 | } 115 | if pos != nil { 116 | OnGround, OnIce, InCobweb, InSweetBerry, OnClimbable, IntersectedLiquid, IntersectedSolid := p.CheckGroundState(pos) 117 | p.OnGround.Set(p.timestampThisTick, OnGround) 118 | p.OnIce.Set(p.timestampThisTick, OnIce) 119 | p.InCobweb.Set(p.timestampThisTick, InCobweb) 120 | p.InSweetBerry.Set(p.timestampThisTick, InSweetBerry) 121 | p.OnClimbable.Set(p.timestampThisTick, OnClimbable) 122 | p.IntersectedLiquid.Set(p.timestampThisTick, IntersectedLiquid) 123 | p.IntersectedSolid.Set(p.timestampThisTick, IntersectedSolid) 124 | } 125 | } 126 | 127 | func (p *InternalPlayer) CheckGroundState(pos *xyron.EntityPositionData) ( 128 | OnGround, 129 | OnIce, 130 | InCobweb, 131 | InSweetBerry, 132 | OnClimbable, 133 | IntersectedLiquid, 134 | IntersectedSolid bool, 135 | ) { 136 | check := func(checkFeature func(*xyron.BlockFeature) bool) func([]*xyron.BlockData) bool { 137 | return func(bb []*xyron.BlockData) bool { 138 | for _, b := range bb { 139 | if checkFeature(b.Feature) { 140 | return true 141 | } 142 | } 143 | return false 144 | } 145 | } 146 | checkSolid := check(func(f *xyron.BlockFeature) bool { return f.IsSolid }) 147 | checkIce := check(func(f *xyron.BlockFeature) bool { return f.IsIce }) 148 | checkCobweb := check(func(f *xyron.BlockFeature) bool { return f.IsCobweb }) 149 | checkSweetBerry := check(func(f *xyron.BlockFeature) bool { return f.IsSweetBerry }) 150 | checkClimbable := check(func(f *xyron.BlockFeature) bool { return f.IsClimbable }) 151 | checkLiquid := check(func(f *xyron.BlockFeature) bool { return f.IsLiquid }) 152 | 153 | OnGround = checkSolid(pos.CollidedBlocks) || checkSolid([]*xyron.BlockData{pos.BelowThatAffectMovement}) 154 | OnIce = checkIce(pos.CollidedBlocks) || checkIce([]*xyron.BlockData{pos.BelowThatAffectMovement}) 155 | InCobweb = checkCobweb(pos.CollidedBlocks) || checkCobweb(pos.IntersectedBlocks) || checkCobweb([]*xyron.BlockData{pos.BelowThatAffectMovement}) 156 | InSweetBerry = checkSweetBerry(pos.CollidedBlocks) || checkSweetBerry(pos.IntersectedBlocks) || checkSweetBerry([]*xyron.BlockData{pos.BelowThatAffectMovement}) 157 | OnClimbable = checkClimbable(pos.CollidedBlocks) || checkClimbable(pos.IntersectedBlocks) || checkClimbable([]*xyron.BlockData{pos.BelowThatAffectMovement}) 158 | IntersectedLiquid = checkLiquid(pos.IntersectedBlocks) || checkLiquid([]*xyron.BlockData{pos.BelowThatAffectMovement}) 159 | IntersectedSolid = checkSolid(pos.IntersectedBlocks) 160 | return 161 | } 162 | 163 | func (p *InternalPlayer) CurrentTimestamp() int64 { 164 | return p.timestampThisTick 165 | } 166 | 167 | func (p *InternalPlayer) Tick() { 168 | p.Motion.Set(p.timestampThisTick, mgl64.Vec3{}) 169 | if !p.OnGround.Current().Get() { 170 | p.InAirTick++ 171 | p.OnGroundTick = 0 172 | } else { 173 | p.InAirTick = 0 174 | p.OnGroundTick++ 175 | } 176 | if p.OnIce.Current().Get() { 177 | p.OnIceTick++ 178 | } else { 179 | p.OnIceTick = 0 180 | } 181 | if p.MotionCoolDown > 0 { 182 | p.MotionCoolDown-- 183 | } 184 | } 185 | 186 | func (p *InternalPlayer) Effect(flag func(feature *xyron.EffectFeature) bool) float64 { 187 | for _, e := range p.effects { 188 | if flag(e) { 189 | return float64(e.Amplifier) 190 | } 191 | } 192 | return 0 193 | } 194 | -------------------------------------------------------------------------------- /src/main/php/prokits/xyron/BlockFeature.php: -------------------------------------------------------------------------------- 1 | xchange.BlockFeature 13 | */ 14 | class BlockFeature extends \Google\Protobuf\Internal\Message 15 | { 16 | /** 17 | * Generated from protobuf field repeated .xchange.AxisAlignedBoundingBox collisionBoxes = 2; 18 | */ 19 | private $collisionBoxes; 20 | /** 21 | * Generated from protobuf field float friction = 3; 22 | */ 23 | protected $friction = 0.0; 24 | /** 25 | * Generated from protobuf field bool isSolid = 4; 26 | */ 27 | protected $isSolid = false; 28 | /** 29 | * Generated from protobuf field bool isLiquid = 5; 30 | */ 31 | protected $isLiquid = false; 32 | /** 33 | * Generated from protobuf field bool isAir = 6; 34 | */ 35 | protected $isAir = false; 36 | /** 37 | * Generated from protobuf field bool isSlime = 7; 38 | */ 39 | protected $isSlime = false; 40 | /** 41 | * Generated from protobuf field bool isClimbable = 8; 42 | */ 43 | protected $isClimbable = false; 44 | /** 45 | * Generated from protobuf field bool isIce = 9; 46 | */ 47 | protected $isIce = false; 48 | /** 49 | * Generated from protobuf field bool isCobweb = 10; 50 | */ 51 | protected $isCobweb = false; 52 | /** 53 | * Generated from protobuf field bool isSweetBerry = 11; 54 | */ 55 | protected $isSweetBerry = false; 56 | 57 | /** 58 | * Constructor. 59 | * 60 | * @param array $data { 61 | * Optional. Data for populating the Message object. 62 | * 63 | * @type array<\prokits\xyron\AxisAlignedBoundingBox>|\Google\Protobuf\Internal\RepeatedField $collisionBoxes 64 | * @type float $friction 65 | * @type bool $isSolid 66 | * @type bool $isLiquid 67 | * @type bool $isAir 68 | * @type bool $isSlime 69 | * @type bool $isClimbable 70 | * @type bool $isIce 71 | * @type bool $isCobweb 72 | * @type bool $isSweetBerry 73 | * } 74 | */ 75 | public function __construct($data = NULL) { 76 | \GPBMetadata\PrimitiveTypes::initOnce(); 77 | parent::__construct($data); 78 | } 79 | 80 | /** 81 | * Generated from protobuf field repeated .xchange.AxisAlignedBoundingBox collisionBoxes = 2; 82 | * @return \Google\Protobuf\Internal\RepeatedField 83 | */ 84 | public function getCollisionBoxes() 85 | { 86 | return $this->collisionBoxes; 87 | } 88 | 89 | /** 90 | * Generated from protobuf field repeated .xchange.AxisAlignedBoundingBox collisionBoxes = 2; 91 | * @param array<\prokits\xyron\AxisAlignedBoundingBox>|\Google\Protobuf\Internal\RepeatedField $var 92 | * @return $this 93 | */ 94 | public function setCollisionBoxes($var) 95 | { 96 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \prokits\xyron\AxisAlignedBoundingBox::class); 97 | $this->collisionBoxes = $arr; 98 | 99 | return $this; 100 | } 101 | 102 | /** 103 | * Generated from protobuf field float friction = 3; 104 | * @return float 105 | */ 106 | public function getFriction() 107 | { 108 | return $this->friction; 109 | } 110 | 111 | /** 112 | * Generated from protobuf field float friction = 3; 113 | * @param float $var 114 | * @return $this 115 | */ 116 | public function setFriction($var) 117 | { 118 | GPBUtil::checkFloat($var); 119 | $this->friction = $var; 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * Generated from protobuf field bool isSolid = 4; 126 | * @return bool 127 | */ 128 | public function getIsSolid() 129 | { 130 | return $this->isSolid; 131 | } 132 | 133 | /** 134 | * Generated from protobuf field bool isSolid = 4; 135 | * @param bool $var 136 | * @return $this 137 | */ 138 | public function setIsSolid($var) 139 | { 140 | GPBUtil::checkBool($var); 141 | $this->isSolid = $var; 142 | 143 | return $this; 144 | } 145 | 146 | /** 147 | * Generated from protobuf field bool isLiquid = 5; 148 | * @return bool 149 | */ 150 | public function getIsLiquid() 151 | { 152 | return $this->isLiquid; 153 | } 154 | 155 | /** 156 | * Generated from protobuf field bool isLiquid = 5; 157 | * @param bool $var 158 | * @return $this 159 | */ 160 | public function setIsLiquid($var) 161 | { 162 | GPBUtil::checkBool($var); 163 | $this->isLiquid = $var; 164 | 165 | return $this; 166 | } 167 | 168 | /** 169 | * Generated from protobuf field bool isAir = 6; 170 | * @return bool 171 | */ 172 | public function getIsAir() 173 | { 174 | return $this->isAir; 175 | } 176 | 177 | /** 178 | * Generated from protobuf field bool isAir = 6; 179 | * @param bool $var 180 | * @return $this 181 | */ 182 | public function setIsAir($var) 183 | { 184 | GPBUtil::checkBool($var); 185 | $this->isAir = $var; 186 | 187 | return $this; 188 | } 189 | 190 | /** 191 | * Generated from protobuf field bool isSlime = 7; 192 | * @return bool 193 | */ 194 | public function getIsSlime() 195 | { 196 | return $this->isSlime; 197 | } 198 | 199 | /** 200 | * Generated from protobuf field bool isSlime = 7; 201 | * @param bool $var 202 | * @return $this 203 | */ 204 | public function setIsSlime($var) 205 | { 206 | GPBUtil::checkBool($var); 207 | $this->isSlime = $var; 208 | 209 | return $this; 210 | } 211 | 212 | /** 213 | * Generated from protobuf field bool isClimbable = 8; 214 | * @return bool 215 | */ 216 | public function getIsClimbable() 217 | { 218 | return $this->isClimbable; 219 | } 220 | 221 | /** 222 | * Generated from protobuf field bool isClimbable = 8; 223 | * @param bool $var 224 | * @return $this 225 | */ 226 | public function setIsClimbable($var) 227 | { 228 | GPBUtil::checkBool($var); 229 | $this->isClimbable = $var; 230 | 231 | return $this; 232 | } 233 | 234 | /** 235 | * Generated from protobuf field bool isIce = 9; 236 | * @return bool 237 | */ 238 | public function getIsIce() 239 | { 240 | return $this->isIce; 241 | } 242 | 243 | /** 244 | * Generated from protobuf field bool isIce = 9; 245 | * @param bool $var 246 | * @return $this 247 | */ 248 | public function setIsIce($var) 249 | { 250 | GPBUtil::checkBool($var); 251 | $this->isIce = $var; 252 | 253 | return $this; 254 | } 255 | 256 | /** 257 | * Generated from protobuf field bool isCobweb = 10; 258 | * @return bool 259 | */ 260 | public function getIsCobweb() 261 | { 262 | return $this->isCobweb; 263 | } 264 | 265 | /** 266 | * Generated from protobuf field bool isCobweb = 10; 267 | * @param bool $var 268 | * @return $this 269 | */ 270 | public function setIsCobweb($var) 271 | { 272 | GPBUtil::checkBool($var); 273 | $this->isCobweb = $var; 274 | 275 | return $this; 276 | } 277 | 278 | /** 279 | * Generated from protobuf field bool isSweetBerry = 11; 280 | * @return bool 281 | */ 282 | public function getIsSweetBerry() 283 | { 284 | return $this->isSweetBerry; 285 | } 286 | 287 | /** 288 | * Generated from protobuf field bool isSweetBerry = 11; 289 | * @param bool $var 290 | * @return $this 291 | */ 292 | public function setIsSweetBerry($var) 293 | { 294 | GPBUtil::checkBool($var); 295 | $this->isSweetBerry = $var; 296 | 297 | return $this; 298 | } 299 | 300 | } 301 | 302 | -------------------------------------------------------------------------------- /xyron/xchange_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc v4.23.1 5 | // source: xchange.proto 6 | 7 | package xyron 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | emptypb "google.golang.org/protobuf/types/known/emptypb" 15 | ) 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the grpc package it is being compiled against. 19 | // Requires gRPC-Go v1.32.0 or later. 20 | const _ = grpc.SupportPackageIsVersion7 21 | 22 | // AnticheatClient is the client API for Anticheat service. 23 | // 24 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 25 | type AnticheatClient interface { 26 | AddPlayer(ctx context.Context, in *AddPlayerRequest, opts ...grpc.CallOption) (*PlayerReceipt, error) 27 | RemovePlayer(ctx context.Context, in *PlayerReceipt, opts ...grpc.CallOption) (*emptypb.Empty, error) 28 | Report(ctx context.Context, in *ReportData, opts ...grpc.CallOption) (*ReportResponse, error) 29 | ReportBatched(ctx context.Context, in *BatchedReportData, opts ...grpc.CallOption) (*BatchedReportResponse, error) 30 | } 31 | 32 | type anticheatClient struct { 33 | cc grpc.ClientConnInterface 34 | } 35 | 36 | func NewAnticheatClient(cc grpc.ClientConnInterface) AnticheatClient { 37 | return &anticheatClient{cc} 38 | } 39 | 40 | func (c *anticheatClient) AddPlayer(ctx context.Context, in *AddPlayerRequest, opts ...grpc.CallOption) (*PlayerReceipt, error) { 41 | out := new(PlayerReceipt) 42 | err := c.cc.Invoke(ctx, "/xchange.Anticheat/AddPlayer", in, out, opts...) 43 | if err != nil { 44 | return nil, err 45 | } 46 | return out, nil 47 | } 48 | 49 | func (c *anticheatClient) RemovePlayer(ctx context.Context, in *PlayerReceipt, opts ...grpc.CallOption) (*emptypb.Empty, error) { 50 | out := new(emptypb.Empty) 51 | err := c.cc.Invoke(ctx, "/xchange.Anticheat/RemovePlayer", in, out, opts...) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return out, nil 56 | } 57 | 58 | func (c *anticheatClient) Report(ctx context.Context, in *ReportData, opts ...grpc.CallOption) (*ReportResponse, error) { 59 | out := new(ReportResponse) 60 | err := c.cc.Invoke(ctx, "/xchange.Anticheat/Report", in, out, opts...) 61 | if err != nil { 62 | return nil, err 63 | } 64 | return out, nil 65 | } 66 | 67 | func (c *anticheatClient) ReportBatched(ctx context.Context, in *BatchedReportData, opts ...grpc.CallOption) (*BatchedReportResponse, error) { 68 | out := new(BatchedReportResponse) 69 | err := c.cc.Invoke(ctx, "/xchange.Anticheat/ReportBatched", in, out, opts...) 70 | if err != nil { 71 | return nil, err 72 | } 73 | return out, nil 74 | } 75 | 76 | // AnticheatServer is the server API for Anticheat service. 77 | // All implementations must embed UnimplementedAnticheatServer 78 | // for forward compatibility 79 | type AnticheatServer interface { 80 | AddPlayer(context.Context, *AddPlayerRequest) (*PlayerReceipt, error) 81 | RemovePlayer(context.Context, *PlayerReceipt) (*emptypb.Empty, error) 82 | Report(context.Context, *ReportData) (*ReportResponse, error) 83 | ReportBatched(context.Context, *BatchedReportData) (*BatchedReportResponse, error) 84 | mustEmbedUnimplementedAnticheatServer() 85 | } 86 | 87 | // UnimplementedAnticheatServer must be embedded to have forward compatible implementations. 88 | type UnimplementedAnticheatServer struct { 89 | } 90 | 91 | func (UnimplementedAnticheatServer) AddPlayer(context.Context, *AddPlayerRequest) (*PlayerReceipt, error) { 92 | return nil, status.Errorf(codes.Unimplemented, "method AddPlayer not implemented") 93 | } 94 | func (UnimplementedAnticheatServer) RemovePlayer(context.Context, *PlayerReceipt) (*emptypb.Empty, error) { 95 | return nil, status.Errorf(codes.Unimplemented, "method RemovePlayer not implemented") 96 | } 97 | func (UnimplementedAnticheatServer) Report(context.Context, *ReportData) (*ReportResponse, error) { 98 | return nil, status.Errorf(codes.Unimplemented, "method Report not implemented") 99 | } 100 | func (UnimplementedAnticheatServer) ReportBatched(context.Context, *BatchedReportData) (*BatchedReportResponse, error) { 101 | return nil, status.Errorf(codes.Unimplemented, "method ReportBatched not implemented") 102 | } 103 | func (UnimplementedAnticheatServer) mustEmbedUnimplementedAnticheatServer() {} 104 | 105 | // UnsafeAnticheatServer may be embedded to opt out of forward compatibility for this service. 106 | // Use of this interface is not recommended, as added methods to AnticheatServer will 107 | // result in compilation errors. 108 | type UnsafeAnticheatServer interface { 109 | mustEmbedUnimplementedAnticheatServer() 110 | } 111 | 112 | func RegisterAnticheatServer(s grpc.ServiceRegistrar, srv AnticheatServer) { 113 | s.RegisterService(&Anticheat_ServiceDesc, srv) 114 | } 115 | 116 | func _Anticheat_AddPlayer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 117 | in := new(AddPlayerRequest) 118 | if err := dec(in); err != nil { 119 | return nil, err 120 | } 121 | if interceptor == nil { 122 | return srv.(AnticheatServer).AddPlayer(ctx, in) 123 | } 124 | info := &grpc.UnaryServerInfo{ 125 | Server: srv, 126 | FullMethod: "/xchange.Anticheat/AddPlayer", 127 | } 128 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 129 | return srv.(AnticheatServer).AddPlayer(ctx, req.(*AddPlayerRequest)) 130 | } 131 | return interceptor(ctx, in, info, handler) 132 | } 133 | 134 | func _Anticheat_RemovePlayer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 135 | in := new(PlayerReceipt) 136 | if err := dec(in); err != nil { 137 | return nil, err 138 | } 139 | if interceptor == nil { 140 | return srv.(AnticheatServer).RemovePlayer(ctx, in) 141 | } 142 | info := &grpc.UnaryServerInfo{ 143 | Server: srv, 144 | FullMethod: "/xchange.Anticheat/RemovePlayer", 145 | } 146 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 147 | return srv.(AnticheatServer).RemovePlayer(ctx, req.(*PlayerReceipt)) 148 | } 149 | return interceptor(ctx, in, info, handler) 150 | } 151 | 152 | func _Anticheat_Report_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 153 | in := new(ReportData) 154 | if err := dec(in); err != nil { 155 | return nil, err 156 | } 157 | if interceptor == nil { 158 | return srv.(AnticheatServer).Report(ctx, in) 159 | } 160 | info := &grpc.UnaryServerInfo{ 161 | Server: srv, 162 | FullMethod: "/xchange.Anticheat/Report", 163 | } 164 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 165 | return srv.(AnticheatServer).Report(ctx, req.(*ReportData)) 166 | } 167 | return interceptor(ctx, in, info, handler) 168 | } 169 | 170 | func _Anticheat_ReportBatched_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 171 | in := new(BatchedReportData) 172 | if err := dec(in); err != nil { 173 | return nil, err 174 | } 175 | if interceptor == nil { 176 | return srv.(AnticheatServer).ReportBatched(ctx, in) 177 | } 178 | info := &grpc.UnaryServerInfo{ 179 | Server: srv, 180 | FullMethod: "/xchange.Anticheat/ReportBatched", 181 | } 182 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 183 | return srv.(AnticheatServer).ReportBatched(ctx, req.(*BatchedReportData)) 184 | } 185 | return interceptor(ctx, in, info, handler) 186 | } 187 | 188 | // Anticheat_ServiceDesc is the grpc.ServiceDesc for Anticheat service. 189 | // It's only intended for direct use with grpc.RegisterService, 190 | // and not to be introspected or modified (even as a copy) 191 | var Anticheat_ServiceDesc = grpc.ServiceDesc{ 192 | ServiceName: "xchange.Anticheat", 193 | HandlerType: (*AnticheatServer)(nil), 194 | Methods: []grpc.MethodDesc{ 195 | { 196 | MethodName: "AddPlayer", 197 | Handler: _Anticheat_AddPlayer_Handler, 198 | }, 199 | { 200 | MethodName: "RemovePlayer", 201 | Handler: _Anticheat_RemovePlayer_Handler, 202 | }, 203 | { 204 | MethodName: "Report", 205 | Handler: _Anticheat_Report_Handler, 206 | }, 207 | { 208 | MethodName: "ReportBatched", 209 | Handler: _Anticheat_ReportBatched_Handler, 210 | }, 211 | }, 212 | Streams: []grpc.StreamDesc{}, 213 | Metadata: "xchange.proto", 214 | } 215 | -------------------------------------------------------------------------------- /anticheat/handlers.go: -------------------------------------------------------------------------------- 1 | package anticheat 2 | 3 | import ( 4 | "github.com/blackjack200/xyron/xyron" 5 | "time" 6 | ) 7 | 8 | func (s *SimpleAnticheat) handleData(p *InternalPlayer, tdata map[int64]*xyron.TimestampedReportData) (r []*xyron.JudgementData) { 9 | var keys []int64 10 | for timestamp, _ := range tdata { 11 | keys = append(keys, timestamp) 12 | } 13 | sorted := ComparableSlice[int64](keys) 14 | sorted.Sort() 15 | p.lastReport = time.Now() 16 | for _, timestamp := range sorted { 17 | p.timestampThisTick = timestamp 18 | for _, wdata := range tdata[timestamp].Data { 19 | for _, c := range p.checks { 20 | c := c 21 | data := s.callHandlers(p, c, wdata) 22 | r = append(r, data...) 23 | } 24 | s.tickPlayer(p, wdata) 25 | } 26 | p.Tick() 27 | } 28 | return 29 | } 30 | 31 | func (s *SimpleAnticheat) tickPlayer(p *InternalPlayer, wdata *xyron.WildcardReportData) { 32 | switch data := wdata.Data.(type) { 33 | case *xyron.WildcardReportData_ActionData: 34 | p.SetLocation(data.ActionData.Position) 35 | switch data.ActionData.Action { 36 | case xyron.PlayerAction_Jump: 37 | p.Jump.Set(p.timestampThisTick, p.Effect(func(f *xyron.EffectFeature) bool { 38 | return f.IsJumpBoost 39 | })) 40 | case xyron.PlayerAction_StartSprint: 41 | p.Sprinting.Set(p.timestampThisTick, true) 42 | case xyron.PlayerAction_StopSprint: 43 | p.Sprinting.Set(p.timestampThisTick, false) 44 | case xyron.PlayerAction_StartSneak: 45 | p.Sneaking.Set(p.timestampThisTick, true) 46 | case xyron.PlayerAction_StopSneak: 47 | p.Sneaking.Set(p.timestampThisTick, false) 48 | case xyron.PlayerAction_StartGliding: 49 | p.Gliding.Set(p.timestampThisTick, true) 50 | case xyron.PlayerAction_StopGliding: 51 | p.Gliding.Set(p.timestampThisTick, false) 52 | case xyron.PlayerAction_StartSwimming: 53 | p.Swimming.Set(p.timestampThisTick, true) 54 | case xyron.PlayerAction_StopSwimming: 55 | p.Swimming.Set(p.timestampThisTick, false) 56 | case xyron.PlayerAction_StartSprintFlying: 57 | p.Flying.Set(p.timestampThisTick, true) 58 | case xyron.PlayerAction_StopSprintFlying: 59 | p.Flying.Set(p.timestampThisTick, false) 60 | case xyron.PlayerAction_OpenInventory: 61 | p.OpenInventory.Set(p.timestampThisTick, true) 62 | case xyron.PlayerAction_CloseInventory: 63 | p.CloseInventory.Set(p.timestampThisTick, true) 64 | default: 65 | s.log.Errorf("unhandled action data: %v", data.ActionData.Action) 66 | } 67 | case *xyron.WildcardReportData_MoveData: 68 | p.SetLocation(data.MoveData.NewPosition) 69 | if data.MoveData.Teleport { 70 | p.Teleport.Set(p.timestampThisTick, toVec3(data.MoveData.NewPosition.Position)) 71 | } 72 | case *xyron.WildcardReportData_PlaceBlockData: 73 | p.PlaceBlock.Set(p.timestampThisTick, data.PlaceBlockData) 74 | case *xyron.WildcardReportData_BreakBlockData: 75 | p.BreakBlock.Set(p.timestampThisTick, data.BreakBlockData) 76 | case *xyron.WildcardReportData_EatFoodData: 77 | p.Eat.Set(p.timestampThisTick, data.EatFoodData.Status == xyron.ConsumeStatus_Stop) 78 | case *xyron.WildcardReportData_AttackData: 79 | p.Attack.Set(p.timestampThisTick, data.AttackData.Data) 80 | case *xyron.WildcardReportData_EffectData: 81 | p.effects = data.EffectData.Effect 82 | case *xyron.WildcardReportData_GameModeData: 83 | p.GameMode = data.GameModeData.GameMode 84 | case *xyron.WildcardReportData_MotionData: 85 | motion := data.MotionData.Motion 86 | p.Motion.Set(p.timestampThisTick, toVec3(motion)) 87 | p.MotionCoolDown += int64(((motion.X+motion.Y)/2 + 2) * 15) 88 | case *xyron.WildcardReportData_InputModeData: 89 | p.Input = data.InputModeData.InputMode 90 | case *xyron.WildcardReportData_LifeData: 91 | p.Alive.Set(p.timestampThisTick, data.LifeData.Alive) 92 | case *xyron.WildcardReportData_HeldItemChangeData: 93 | p.HeldItem.Set(p.timestampThisTick, data.HeldItemChangeData.Item) 94 | default: 95 | s.log.Errorf("unhandled data: %T", data) 96 | } 97 | } 98 | 99 | // ActionDataHandler handles *xyron.WildcardReportData_ActionData 100 | type ActionDataHandler interface { 101 | HandleActionData(*InternalPlayer, *xyron.PlayerActionData) *xyron.JudgementData 102 | } 103 | 104 | // MoveDataHandler handles *xyron.WildcardReportData_MoveData 105 | type MoveDataHandler interface { 106 | HandleMoveData(*InternalPlayer, *xyron.PlayerMoveData) *xyron.JudgementData 107 | } 108 | 109 | // PlaceBlockDataHandler handles *xyron.WildcardReportData_PlaceBlockData 110 | type PlaceBlockDataHandler interface { 111 | HandlePlaceBlockData(*InternalPlayer, *xyron.PlayerPlaceBlockData) *xyron.JudgementData 112 | } 113 | 114 | // BreakBlockDataHandler handles *xyron.WildcardReportData_BreakBlockData 115 | type BreakBlockDataHandler interface { 116 | HandleBreakBlockData(*InternalPlayer, *xyron.PlayerBreakBlockData) *xyron.JudgementData 117 | } 118 | 119 | // EatFoodDataHandler handles *xyron.WildcardReportData_EatFoodData 120 | type EatFoodDataHandler interface { 121 | HandleEatFoodData(*InternalPlayer, *xyron.PlayerEatFoodData) *xyron.JudgementData 122 | } 123 | 124 | // AttackDataHandler handles *xyron.WildcardReportData_AttackData 125 | type AttackDataHandler interface { 126 | HandleAttackData(*InternalPlayer, *xyron.PlayerAttackData) *xyron.JudgementData 127 | } 128 | 129 | // EffectDataHandler handles *xyron.WildcardReportData_EffectData 130 | type EffectDataHandler interface { 131 | HandleEffectData(*InternalPlayer, *xyron.PlayerEffectData) *xyron.JudgementData 132 | } 133 | 134 | // GameModeDataHandler handles *xyron.WildcardReportData_GameModeData 135 | type GameModeDataHandler interface { 136 | HandleGameModeData(*InternalPlayer, *xyron.PlayerGameModeData) *xyron.JudgementData 137 | } 138 | 139 | // MotionDataHandler handles *xyron.WildcardReportData_MotionData 140 | type MotionDataHandler interface { 141 | HandleMotionData(*InternalPlayer, *xyron.PlayerMotionData) *xyron.JudgementData 142 | } 143 | 144 | // InputModeDataHandler handles *xyron.WildcardReportData_InputModeData 145 | type InputModeDataHandler interface { 146 | HandleInputModeData(*InternalPlayer, *xyron.PlayerInputModeData) *xyron.JudgementData 147 | } 148 | 149 | // HeldItemChangeDataHandler handles *xyron.WildcardReportData_HeldItemChangeData 150 | type HeldItemChangeDataHandler interface { 151 | HandleHeldItemChangeData(*InternalPlayer, *xyron.PlayerHeldItemChangeData) *xyron.JudgementData 152 | } 153 | 154 | func (s *SimpleAnticheat) callHandlers(p *InternalPlayer, c any, wdata *xyron.WildcardReportData) []*xyron.JudgementData { 155 | var r []*xyron.JudgementData 156 | if handler, ok := c.(ActionDataHandler); ok { 157 | if data, ok := wdata.Data.(*xyron.WildcardReportData_ActionData); ok { 158 | r = append(r, handler.HandleActionData(p, data.ActionData)) 159 | } 160 | } 161 | if handler, ok := c.(MoveDataHandler); ok { 162 | if data, ok := wdata.Data.(*xyron.WildcardReportData_MoveData); ok { 163 | r = append(r, handler.HandleMoveData(p, data.MoveData)) 164 | } 165 | } 166 | if handler, ok := c.(PlaceBlockDataHandler); ok { 167 | if data, ok := wdata.Data.(*xyron.WildcardReportData_PlaceBlockData); ok { 168 | r = append(r, handler.HandlePlaceBlockData(p, data.PlaceBlockData)) 169 | } 170 | } 171 | if handler, ok := c.(BreakBlockDataHandler); ok { 172 | if data, ok := wdata.Data.(*xyron.WildcardReportData_BreakBlockData); ok { 173 | r = append(r, handler.HandleBreakBlockData(p, data.BreakBlockData)) 174 | } 175 | } 176 | if handler, ok := c.(EatFoodDataHandler); ok { 177 | if data, ok := wdata.Data.(*xyron.WildcardReportData_EatFoodData); ok { 178 | r = append(r, handler.HandleEatFoodData(p, data.EatFoodData)) 179 | } 180 | } 181 | if handler, ok := c.(AttackDataHandler); ok { 182 | if data, ok := wdata.Data.(*xyron.WildcardReportData_AttackData); ok { 183 | r = append(r, handler.HandleAttackData(p, data.AttackData)) 184 | } 185 | } 186 | if handler, ok := c.(EffectDataHandler); ok { 187 | if data, ok := wdata.Data.(*xyron.WildcardReportData_EffectData); ok { 188 | r = append(r, handler.HandleEffectData(p, data.EffectData)) 189 | } 190 | } 191 | if handler, ok := c.(GameModeDataHandler); ok { 192 | if data, ok := wdata.Data.(*xyron.WildcardReportData_GameModeData); ok { 193 | r = append(r, handler.HandleGameModeData(p, data.GameModeData)) 194 | } 195 | } 196 | if handler, ok := c.(MotionDataHandler); ok { 197 | if data, ok := wdata.Data.(*xyron.WildcardReportData_MotionData); ok { 198 | r = append(r, handler.HandleMotionData(p, data.MotionData)) 199 | } 200 | } 201 | if handler, ok := c.(InputModeDataHandler); ok { 202 | if data, ok := wdata.Data.(*xyron.WildcardReportData_InputModeData); ok { 203 | r = append(r, handler.HandleInputModeData(p, data.InputModeData)) 204 | } 205 | } 206 | if handler, ok := c.(HeldItemChangeDataHandler); ok { 207 | if data, ok := wdata.Data.(*xyron.WildcardReportData_HeldItemChangeData); ok { 208 | r = append(r, handler.HandleHeldItemChangeData(p, data.HeldItemChangeData)) 209 | } 210 | } 211 | 212 | var result []*xyron.JudgementData 213 | 214 | for _, item := range r { 215 | if item != nil { 216 | result = append(result, item) 217 | } 218 | } 219 | return result 220 | } 221 | --------------------------------------------------------------------------------