├── ACTransmitter
├── src
│ └── main
│ │ ├── resources
│ │ ├── config.yml
│ │ └── plugin.yml
│ │ └── java
│ │ └── com
│ │ └── nort721
│ │ └── transmitter
│ │ ├── utils
│ │ ├── CompressionUtil.java
│ │ └── wrappers
│ │ │ └── WrapperPlayClientFlying.java
│ │ ├── listeners
│ │ ├── BukkitListener.java
│ │ └── PacketsListener.java
│ │ ├── cserver
│ │ ├── ComputationServerSender.java
│ │ └── ComputationServerListener.java
│ │ └── ACTransmitter.java
├── target
│ ├── classes
│ │ ├── config.yml
│ │ ├── com
│ │ │ └── nort721
│ │ │ │ └── transmitter
│ │ │ │ ├── ACTransmitter.class
│ │ │ │ └── PacketsListener.class
│ │ └── plugin.yml
│ ├── maven-status
│ │ └── maven-compiler-plugin
│ │ │ ├── testCompile
│ │ │ └── default-testCompile
│ │ │ │ ├── inputFiles.lst
│ │ │ │ └── createdFiles.lst
│ │ │ └── compile
│ │ │ └── default-compile
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ ├── original-ACTransmitter-Build-0.jar
│ └── maven-archiver
│ │ └── pom.properties
├── local_repos
│ └── ProtocolLib.jar
├── ACTransmitter.iml
└── pom.xml
├── ComputationServer
├── go.mod
├── Launcher.go
└── sys
│ ├── sysutils.go
│ ├── packets.go
│ ├── profiles.go
│ ├── cserver.go
│ ├── checks.go
│ └── processors.go
├── .gitignore
├── README.md
└── LICENSE
/ACTransmitter/src/main/resources/config.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ACTransmitter/target/classes/config.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ComputationServer/go.mod:
--------------------------------------------------------------------------------
1 | module CloudAC/ComputationServer
2 |
3 | go 1.17
4 |
--------------------------------------------------------------------------------
/ACTransmitter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ACTransmitter/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ACTransmitter/local_repos/ProtocolLib.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xntpower/CloudAC/HEAD/ACTransmitter/local_repos/ProtocolLib.jar
--------------------------------------------------------------------------------
/ACTransmitter/target/original-ACTransmitter-Build-0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xntpower/CloudAC/HEAD/ACTransmitter/target/original-ACTransmitter-Build-0.jar
--------------------------------------------------------------------------------
/ComputationServer/Launcher.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import cserver "CloudAC/ComputationServer/sys"
4 |
5 | // entry point
6 | func main() {
7 | cserver.Start()
8 | }
9 |
--------------------------------------------------------------------------------
/ACTransmitter/target/maven-archiver/pom.properties:
--------------------------------------------------------------------------------
1 | #Generated by Maven
2 | #Fri Jun 17 01:27:03 IDT 2022
3 | version=Build-0
4 | groupId=com.nort721
5 | artifactId=ACTransmitter
6 |
--------------------------------------------------------------------------------
/ACTransmitter/target/classes/com/nort721/transmitter/ACTransmitter.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xntpower/CloudAC/HEAD/ACTransmitter/target/classes/com/nort721/transmitter/ACTransmitter.class
--------------------------------------------------------------------------------
/ACTransmitter/target/classes/com/nort721/transmitter/PacketsListener.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xntpower/CloudAC/HEAD/ACTransmitter/target/classes/com/nort721/transmitter/PacketsListener.class
--------------------------------------------------------------------------------
/ACTransmitter/target/classes/plugin.yml:
--------------------------------------------------------------------------------
1 | name: ACTransmitter
2 | version: Build-0
3 | api-version: 1.13
4 | main: com.nort721.transmitter.ACTransmitter
5 | author: Nort721
6 | description: An anticheat data transmision unit
7 | depend: [ ProtocolLib ]
--------------------------------------------------------------------------------
/ACTransmitter/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | name: ACTransmitter
2 | version: ${project.version}
3 | api-version: 1.13
4 | main: com.nort721.transmitter.ACTransmitter
5 | author: Nort721
6 | description: An anticheat data transmision unit
7 | depend: [ ProtocolLib ]
--------------------------------------------------------------------------------
/ComputationServer/sys/sysutils.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | func Encode(str string) string {
4 | // ToDo insert compression algorithm here
5 | return str
6 | }
7 |
8 | func Decode(str string) string {
9 | // ToDo insert exctraction algorithm here
10 | return str
11 | }
12 |
--------------------------------------------------------------------------------
/ComputationServer/sys/packets.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | type PacketType int64
4 |
5 | const (
6 | JOIN PacketType = 0
7 | LEAVE PacketType = 1
8 | FLYING PacketType = 2
9 | CLIENT_ABILITIES PacketType = 3
10 | SERVER_ABILITIES PacketType = 4
11 | )
12 |
--------------------------------------------------------------------------------
/ACTransmitter/src/main/java/com/nort721/transmitter/utils/CompressionUtil.java:
--------------------------------------------------------------------------------
1 | package com.nort721.transmitter.utils;
2 |
3 | import lombok.experimental.UtilityClass;
4 |
5 | @UtilityClass
6 | public class CompressionUtil {
7 |
8 | public static String encode(String str) {
9 | // ToDo insert compression algorithm here
10 | return str;
11 | }
12 |
13 | public static String decode(String str) {
14 | // ToDo insert exctraction algorithm here
15 | return str;
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/ACTransmitter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst:
--------------------------------------------------------------------------------
1 | com\nort721\transmitter\ComputationServerListener$ReplyHandler.class
2 | com\nort721\transmitter\ComputationServerSender.class
3 | com\nort721\transmitter\ComputationServerListener$ReplyHandler$1.class
4 | com\nort721\transmitter\PacketsListener.class
5 | com\nort721\transmitter\WrapperPlayClientFlying.class
6 | com\nort721\transmitter\BukkitListener.class
7 | com\nort721\transmitter\ACTransmitter.class
8 | com\nort721\transmitter\ComputationServerListener.class
9 |
--------------------------------------------------------------------------------
/ACTransmitter/ACTransmitter.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | SPIGOT
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ACTransmitter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst:
--------------------------------------------------------------------------------
1 | C:\Users\Nort\go\src\CloudAC\ACTransmitter\src\main\java\com\nort721\transmitter\PacketsListener.java
2 | C:\Users\Nort\go\src\CloudAC\ACTransmitter\src\main\java\com\nort721\transmitter\ACTransmitter.java
3 | C:\Users\Nort\go\src\CloudAC\ACTransmitter\src\main\java\com\nort721\transmitter\WrapperPlayClientFlying.java
4 | C:\Users\Nort\go\src\CloudAC\ACTransmitter\src\main\java\com\nort721\transmitter\ComputationServerListener.java
5 | C:\Users\Nort\go\src\CloudAC\ACTransmitter\src\main\java\com\nort721\transmitter\BukkitListener.java
6 | C:\Users\Nort\go\src\CloudAC\ACTransmitter\src\main\java\com\nort721\transmitter\ComputationServerSender.java
7 |
--------------------------------------------------------------------------------
/ACTransmitter/src/main/java/com/nort721/transmitter/listeners/BukkitListener.java:
--------------------------------------------------------------------------------
1 | package com.nort721.transmitter.listeners;
2 |
3 | import com.nort721.transmitter.ACTransmitter;
4 | import org.bukkit.entity.Player;
5 | import org.bukkit.event.EventHandler;
6 | import org.bukkit.event.EventPriority;
7 | import org.bukkit.event.Listener;
8 | import org.bukkit.event.player.PlayerQuitEvent;
9 |
10 | public class BukkitListener implements Listener {
11 |
12 | public BukkitListener(ACTransmitter acTransmitter) {
13 | acTransmitter.getServer().getPluginManager().registerEvents(this, acTransmitter);
14 | }
15 |
16 | @EventHandler(priority = EventPriority.LOWEST)
17 | public void onPlayerQuit(PlayerQuitEvent e) {
18 | Player player = e.getPlayer();
19 |
20 | String packetData = "1" + "|" +
21 | player.getUniqueId() + "|" +
22 | System.currentTimeMillis();
23 |
24 | ACTransmitter.getInstance().getComputationServerSender().sendDataToServer(packetData);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/ComputationServer/sys/profiles.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | var profile_map = make(map[string]Profile)
4 |
5 | type SpeedCheckData struct {
6 | vl int
7 | lastOffsetH float64
8 | }
9 |
10 | type Location struct {
11 | x float64
12 | y float64
13 | z float64
14 | yaw float32
15 | pitch float32
16 | }
17 |
18 | type Profile struct {
19 | uuid string
20 | isFlyingClient bool
21 | isFlyingServer bool
22 | isAllowedFlightClient bool
23 | isAllowedFlightServer bool
24 | onGround bool
25 | lastOnGround bool
26 | latestLocation Location
27 | lastLocation Location
28 | speedData SpeedCheckData
29 | }
30 |
31 | func Add(uuid string) {
32 | profile_map[uuid] = Profile{uuid, false, false, false, false, true, true, Location{}, Location{}, SpeedCheckData{}}
33 | }
34 |
35 | func Remove(uuid string) {
36 | delete(profile_map, uuid)
37 | }
38 |
39 | func Contains(uuid string) bool {
40 | if _, keyExists := profile_map[uuid]; keyExists {
41 | return true
42 | }
43 | return false
44 | }
45 |
46 | func Get(uuid string) Profile {
47 | return profile_map[uuid]
48 | }
49 |
--------------------------------------------------------------------------------
/ACTransmitter/src/main/java/com/nort721/transmitter/utils/wrappers/WrapperPlayClientFlying.java:
--------------------------------------------------------------------------------
1 | package com.nort721.transmitter.utils.wrappers;
2 |
3 | import com.comphenix.protocol.events.PacketContainer;
4 | import com.comphenix.protocol.events.PacketEvent;
5 |
6 | public class WrapperPlayClientFlying {
7 | private final PacketContainer packetData;
8 |
9 | public WrapperPlayClientFlying(PacketEvent packetEvent) {
10 | packetData = packetEvent.getPacket();
11 | }
12 |
13 | /**
14 | * Retrieve if packet has position.
15 | *
16 | * Notes: true if the packet has position.
17 | *
18 | * @return If packet has position.
19 | */
20 | public boolean hasPosition() {
21 | return packetData.getBooleans().read(1);
22 | }
23 |
24 | /**
25 | * Retrieve if packet has look.
26 | *
27 | * Notes: true if the packet has look.
28 | *
29 | * @return If packet has position.
30 | */
31 | public boolean hasLook() {
32 | return packetData.getBooleans().read(2);
33 | }
34 |
35 | /**
36 | * Retrieve On Ground.
37 | *
38 | * Notes: true if the client is on the ground, False otherwise
39 | *
40 | * @return The current On Ground
41 | */
42 | public boolean getOnGround() {
43 | return packetData.getBooleans().read(0);
44 | }
45 |
46 | /**
47 | * Set On Ground.
48 | *
49 | * @param value - new value.
50 | */
51 | public void setOnGround(boolean value) {
52 | packetData.getBooleans().write(0, value);
53 | }
54 |
55 | public double getX() {
56 | return packetData.getDoubles().read(0);
57 | }
58 |
59 | public double getY() {
60 | return packetData.getDoubles().read(1);
61 | }
62 |
63 | public double getZ() {
64 | return packetData.getDoubles().read(2);
65 | }
66 |
67 | public float getPitch() {
68 | return packetData.getFloat().read(1);
69 | }
70 |
71 | public float getYaw() {
72 | return packetData.getFloat().read(0);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ACTransmitter/src/main/java/com/nort721/transmitter/cserver/ComputationServerSender.java:
--------------------------------------------------------------------------------
1 | package com.nort721.transmitter.cserver;
2 |
3 | import com.nort721.transmitter.utils.CompressionUtil;
4 | import lombok.Getter;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.io.PrintWriter;
10 | import java.net.Socket;
11 |
12 | @Getter
13 | public class ComputationServerSender extends Thread {
14 |
15 | private final String computation_server_address;
16 | private final int computation_server_port;
17 |
18 | private Socket socket;
19 | private BufferedReader input;
20 | private PrintWriter output;
21 |
22 | public ComputationServerSender(String computation_server_address, int computation_server_port) {
23 | this.computation_server_address = computation_server_address;
24 | this.computation_server_port = computation_server_port;
25 | }
26 |
27 | @Override
28 | public void run() {
29 | try {
30 | startCommunication();
31 | } catch (IOException e) {
32 | e.printStackTrace();
33 | }
34 | }
35 |
36 | private void startCommunication() throws IOException {}
37 |
38 | public void sendDataToServer(String data) {
39 | try {
40 |
41 | socket = new Socket(computation_server_address, computation_server_port);
42 |
43 | input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
44 |
45 | output = new PrintWriter(socket.getOutputStream(), true);
46 |
47 | output.println(CompressionUtil.encode(data));
48 |
49 | } catch (IOException e) {
50 | e.printStackTrace();
51 | }
52 | }
53 |
54 | public void closeConnection() {
55 | try {
56 | output.close();
57 | input.close();
58 | socket.close();
59 | } catch (IOException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/ACTransmitter/src/main/java/com/nort721/transmitter/ACTransmitter.java:
--------------------------------------------------------------------------------
1 | package com.nort721.transmitter;
2 |
3 | import com.comphenix.protocol.ProtocolLibrary;
4 | import com.comphenix.protocol.events.PacketAdapter;
5 | import com.nort721.transmitter.cserver.ComputationServerListener;
6 | import com.nort721.transmitter.cserver.ComputationServerSender;
7 | import com.nort721.transmitter.listeners.BukkitListener;
8 | import com.nort721.transmitter.listeners.PacketsListener;
9 | import lombok.Getter;
10 | import org.bukkit.Bukkit;
11 | import org.bukkit.ChatColor;
12 | import org.bukkit.plugin.java.JavaPlugin;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | public class ACTransmitter extends JavaPlugin {
18 |
19 | private final List packetAdapters = new ArrayList<>();
20 |
21 | @Getter private ComputationServerSender computationServerSender;
22 |
23 | /**
24 | * Gets the instance of the plugin that's currently active in memory
25 | * @return An ACTransmitter instance
26 | */
27 | public static ACTransmitter getInstance() {
28 | return getPlugin(ACTransmitter.class);
29 | }
30 |
31 | @Override
32 | public void onEnable() {
33 | new BukkitListener(this);
34 | packetAdapters.add(new PacketsListener(this));
35 |
36 | ComputationServerListener computationServerListener = new ComputationServerListener();
37 | computationServerListener.start();
38 |
39 | computationServerSender = new ComputationServerSender("localhost", 1234);
40 | computationServerSender.start();
41 |
42 | sendConsoleMessage("has been enabled");
43 | }
44 |
45 | @Override
46 | public void onDisable() {
47 | packetAdapters.forEach(ProtocolLibrary.getProtocolManager()::removePacketListener);
48 | computationServerSender.closeConnection();
49 | sendConsoleMessage("has been disabled");
50 | }
51 |
52 | public void sendConsoleMessage(String msg) {
53 | Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[" + getDescription().getName() + "] " + ChatColor.RESET + msg);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/ComputationServer/sys/cserver.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "net"
7 | "strconv"
8 | "strings"
9 | )
10 |
11 | var packetTypes = make(map[string]PacketType)
12 |
13 | func Start() {
14 |
15 | const version string = "Build 0"
16 |
17 | fmt.Println("===================================")
18 | fmt.Println("AntiCheat-ComputationServer " + version)
19 | fmt.Println("===================================")
20 | fmt.Println("")
21 |
22 | packetTypes["0"] = JOIN
23 | packetTypes["1"] = LEAVE
24 | packetTypes["2"] = FLYING
25 | packetTypes["3"] = CLIENT_ABILITIES
26 | packetTypes["4"] = SERVER_ABILITIES
27 |
28 | startServer()
29 | }
30 |
31 | func startServer() {
32 |
33 | const connectionPort int = 1234
34 |
35 | server, _ := net.Listen("tcp", ":"+strconv.Itoa(connectionPort))
36 |
37 | fmt.Println("listening on", connectionPort, " . . .")
38 | fmt.Println("")
39 |
40 | checksList := make([]Check, 2)
41 | processorsList := make([]Processor, 1)
42 |
43 | checksList[0] = CheckAbilties{}
44 | checksList[1] = CheckSpeed{}
45 | processorsList[0] = StatusProcessor{}
46 |
47 | // run loop forever (or until ctrl-c)
48 | for {
49 |
50 | // accept connection
51 | socket, _ := server.Accept()
52 |
53 | // get message, output
54 | message, _ := bufio.NewReader(socket).ReadString('\n')
55 |
56 | // decompress the data
57 | message = Decode(message)
58 |
59 | message = strings.Trim(message, "\n")
60 |
61 | //fmt.Println("received request ->", message)
62 |
63 | executeProcessors(message, processorsList)
64 | executeChecks(message, checksList)
65 | }
66 | }
67 |
68 | func executeProcessors(message string, processeorsList []Processor) {
69 | for i := 0; i < len(processeorsList); i++ {
70 |
71 | args := strings.Split(message, "|")
72 |
73 | processeorsList[i].ProcessesIncomingPacket(packetTypes[args[0]], args)
74 | }
75 | }
76 |
77 | func executeChecks(message string, checksList []Check) {
78 | for i := 0; i < len(checksList); i++ {
79 |
80 | args := strings.Split(message, "|")
81 |
82 | checksList[i].OnPacketReceived(packetTypes[args[0]], args)
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/ComputationServer/sys/checks.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "fmt"
5 | "net"
6 | )
7 |
8 | type Check interface {
9 | OnPacketReceived(packetType PacketType, args []string)
10 | }
11 |
12 | func OnPacketReceived(c Check, packetType PacketType, data []string) {
13 | c.OnPacketReceived(packetType, data)
14 | }
15 |
16 | type CheckAbilties struct {
17 | Text string
18 | }
19 |
20 | func (c CheckAbilties) OnPacketReceived(packetType PacketType, args []string) {
21 | var uuid string = args[1]
22 |
23 | if packetType == CLIENT_ABILITIES {
24 |
25 | profile := Get(uuid)
26 |
27 | if profile.isAllowedFlightClient && !profile.isAllowedFlightServer {
28 | flagPlayer(uuid, "CheckAbilties")
29 | }
30 |
31 | }
32 | }
33 |
34 | type CheckSpeed struct {
35 | Text string
36 | }
37 |
38 | func (c CheckSpeed) OnPacketReceived(packetType PacketType, args []string) {
39 | var uuid string = args[1]
40 |
41 | if packetType == FLYING {
42 |
43 | profile := Get(uuid)
44 |
45 | var from Location = profile.lastLocation
46 | var to Location = profile.latestLocation
47 |
48 | var offsetX float64 = to.x - from.x
49 | var offsetZ float64 = to.x - from.z
50 |
51 | var offsetHSquared float64 = offsetX*offsetX + offsetZ*offsetZ
52 |
53 | // friction in air
54 | var friction float64 = 0.91
55 |
56 | var shiftedLastDist float64 = profile.speedData.lastOffsetH * friction
57 |
58 | var equal float64 = offsetHSquared - shiftedLastDist
59 | var scaledEqual float64 = equal * 138
60 |
61 | vl := profile.speedData.vl
62 |
63 | if !profile.onGround && !profile.lastOnGround {
64 |
65 | //fmt.Println("scaledEqual:", scaledEqual)
66 | if scaledEqual > 1.1 {
67 | //fmt.Println("vl:", vl)
68 | vl += 1
69 | if vl > 2 {
70 | vl = 0
71 | flagPlayer(uuid, "CheckSpeed")
72 | }
73 | } else {
74 | vl = 0
75 | }
76 | }
77 |
78 | profile.speedData.vl = vl
79 |
80 | profile.speedData.lastOffsetH = offsetHSquared
81 |
82 | }
83 | }
84 |
85 | // let the minecraft server know that the player got flagged
86 | func flagPlayer(uuid string, data string) {
87 | fmt.Println("server -> " + data + " -> FLAG!")
88 |
89 | conn, _ := net.Dial("tcp", "localhost:1212")
90 |
91 | var message string = "FLAG|" + uuid + "|" + data
92 |
93 | fmt.Fprintf(conn, message+"\n")
94 | }
95 |
--------------------------------------------------------------------------------
/ComputationServer/sys/processors.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | type Processor interface {
10 | ProcessesIncomingPacket(packetType PacketType, args []string)
11 | }
12 |
13 | func ProcessesIncomingPacket(s Processor, packetType PacketType, data []string) {
14 | s.ProcessesIncomingPacket(packetType, data)
15 | }
16 |
17 | type StatusProcessor struct {
18 | Text string
19 | }
20 |
21 | func (c StatusProcessor) ProcessesIncomingPacket(packetType PacketType, args []string) {
22 | var uuid string = args[1]
23 |
24 | if packetType == JOIN {
25 |
26 | if !Contains(uuid) {
27 | Add(uuid)
28 | fmt.Println("server -> New profile (uuid-" + uuid + ")")
29 | }
30 |
31 | } else if packetType == LEAVE {
32 |
33 | Remove(uuid)
34 | fmt.Println("server -> Removed profile (uuid-" + uuid + ")")
35 |
36 | } else if packetType == FLYING {
37 |
38 | if Contains(uuid) {
39 | x, _ := strconv.ParseFloat(args[6], 64)
40 | y, _ := strconv.ParseFloat(args[7], 64)
41 | z, _ := strconv.ParseFloat(args[8], 64)
42 | yaw, _ := strconv.ParseFloat(args[9], 32)
43 | pitch, _ := strconv.ParseFloat(args[10], 32)
44 | isPos, _ := strconv.ParseBool(args[3])
45 | isLook, _ := strconv.ParseBool(args[4])
46 | onGround, _ := strconv.ParseBool(args[5])
47 |
48 | profile := Get(uuid)
49 |
50 | profile.lastOnGround = profile.onGround
51 | profile.onGround = onGround
52 |
53 | if isPos {
54 | profile.lastLocation.x = profile.latestLocation.x
55 | profile.lastLocation.y = profile.latestLocation.y
56 | profile.lastLocation.z = profile.latestLocation.z
57 |
58 | profile.latestLocation.x = x
59 | profile.latestLocation.y = y
60 | profile.latestLocation.z = z
61 | }
62 |
63 | if isLook {
64 | profile.lastLocation.yaw = profile.latestLocation.yaw
65 | profile.lastLocation.pitch = profile.latestLocation.pitch
66 |
67 | profile.latestLocation.yaw = float32(yaw)
68 | profile.latestLocation.pitch = float32(pitch)
69 | }
70 |
71 | profile_map[uuid] = profile
72 | }
73 |
74 | } else if packetType == CLIENT_ABILITIES {
75 |
76 | if Contains(uuid) {
77 | var isFlying string = args[3]
78 | var isAllowedFlight string = args[4]
79 |
80 | profile := Get(uuid)
81 |
82 | // there is probably a better way to do that, but works for now...
83 | profile.isFlyingClient = strings.Contains(isFlying, "true")
84 | profile.isAllowedFlightClient = strings.Contains(isAllowedFlight, "true")
85 |
86 | profile_map[uuid] = profile
87 | }
88 |
89 | } else if packetType == SERVER_ABILITIES {
90 |
91 | if Contains(uuid) {
92 | var isFlying string = args[3]
93 | var isAllowedFlight string = args[4]
94 |
95 | profile := Get(uuid)
96 |
97 | // there is probably a better way to do that, but works for now...
98 | profile.isFlyingServer = strings.Contains(isFlying, "true")
99 | profile.isAllowedFlightServer = strings.Contains(isAllowedFlight, "true")
100 |
101 | profile_map[uuid] = profile
102 | }
103 |
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/ACTransmitter/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.nort721
8 | ACTransmitter
9 | Build-0
10 |
11 | ACTransmitter
12 |
13 | jar
14 |
15 |
16 | 1.8
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-compiler-plugin
24 | 3.8.1
25 |
26 | ${java.version}
27 | ${java.version}
28 |
29 |
30 |
31 | org.apache.maven.plugins
32 | maven-shade-plugin
33 | 3.2.4
34 |
35 |
36 | package
37 |
38 | shade
39 |
40 |
41 |
42 | false
43 | false
44 | ${project.name}-${project.version}
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | src/main/resources
56 | true
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | spigotmc-repo
71 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/
72 |
73 |
74 |
75 |
76 | jitpack.io
77 | https://jitpack.io
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.projectlombok
87 | lombok
88 | 1.18.22
89 | provided
90 |
91 |
92 |
93 |
94 | com.comphenix.protocol
95 | ProtocolLib
96 | 4.8.0
97 | ${project.basedir}/local_repos/ProtocolLib.jar
98 | system
99 |
100 |
101 |
102 |
103 | org.spigotmc
104 | spigot-api
105 | 1.16.5-R0.1-SNAPSHOT
106 | provided
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/ACTransmitter/src/main/java/com/nort721/transmitter/cserver/ComputationServerListener.java:
--------------------------------------------------------------------------------
1 | package com.nort721.transmitter.cserver;
2 |
3 | import com.nort721.transmitter.ACTransmitter;
4 | import com.nort721.transmitter.utils.CompressionUtil;
5 | import org.bukkit.Bukkit;
6 | import org.bukkit.entity.Player;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.IOException;
10 | import java.io.InputStreamReader;
11 | import java.io.PrintWriter;
12 | import java.net.ServerSocket;
13 | import java.net.Socket;
14 | import java.util.ArrayList;
15 | import java.util.UUID;
16 |
17 | public class ComputationServerListener extends Thread {
18 |
19 | private static final int PORT = 1212;
20 |
21 | @Override
22 | public void run() {
23 | ServerSocket serverSocket;
24 |
25 | try {
26 | serverSocket = new ServerSocket(PORT);
27 | } catch (IOException e) {
28 | e.printStackTrace();
29 | return;
30 | }
31 |
32 | while (true) {
33 |
34 | try {
35 |
36 | Socket socket = serverSocket.accept();
37 |
38 | ReplyHandler replyHandler = new ReplyHandler(socket);
39 |
40 | replyHandler.start();
41 |
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | }
45 |
46 | }
47 | }
48 |
49 | static class ReplyHandler extends Thread {
50 |
51 | Socket socket;
52 | BufferedReader input;
53 | PrintWriter output;
54 |
55 | public ReplyHandler(Socket socket) {
56 | this.socket = socket;
57 |
58 | try {
59 | input = new BufferedReader(new InputStreamReader(socket.getInputStream()));;
60 | output = new PrintWriter(socket.getOutputStream(), true);
61 | } catch (IOException e) {
62 | System.err.println("Error creating streams: " + e.getMessage());
63 | }
64 |
65 | //System.out.println(" -> established secure connection with " + socket.getInetAddress().getHostAddress());
66 | }
67 |
68 | @Override
69 | public void run() {
70 | try {
71 |
72 | String data = CompressionUtil.decode(input.readLine());
73 | System.out.println(socket.getInetAddress().getHostName() + " -> " + data);
74 |
75 | String[] args = getArgs(data, '|');
76 |
77 | if (args[0].equalsIgnoreCase("FLAG")) {
78 | kickPlayerSafely(args[1], args[2]);
79 | }
80 |
81 | // close everything when were done
82 | output.close();
83 | input.close();
84 | socket.close();
85 |
86 | } catch (Exception e) {
87 | e.printStackTrace();
88 | }
89 | }
90 |
91 | private void kickPlayerSafely(String uuid, String data) {
92 | Player player = Bukkit.getPlayer(UUID.fromString(uuid));
93 |
94 | if (player == null) return;
95 |
96 | Bukkit.getServer().getScheduler().runTask(ACTransmitter.getInstance(), new Runnable() {
97 | public void run() {
98 | player.kickPlayer("KICKED FOR CHEATING | " + data);
99 | }
100 | });
101 | }
102 |
103 | private String[] getArgs(String input, char separator) {
104 |
105 | ArrayList args = new ArrayList<>();
106 |
107 | StringBuilder sb = new StringBuilder();
108 |
109 | for (char c : input.toCharArray()) {
110 |
111 | if (c == separator) {
112 | args.add(sb.toString());
113 | sb = new StringBuilder();
114 | } else {
115 | sb.append(c);
116 | }
117 |
118 | }
119 |
120 | args.add(sb.toString());
121 |
122 | String[] arr = new String[args.size()];
123 | args.toArray(arr);
124 |
125 | return arr;
126 | }
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/java,intellij+all,macos,maven
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij+all,macos,maven
4 |
5 | ### Intellij+all ###
6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
8 |
9 | # User-specific stuff
10 | .idea/**/workspace.xml
11 | .idea/**/tasks.xml
12 | .idea/**/usage.statistics.xml
13 | .idea/**/dictionaries
14 | .idea/**/shelf
15 |
16 | # AWS User-specific
17 | .idea/**/aws.xml
18 |
19 | # Generated files
20 | .idea/**/contentModel.xml
21 |
22 | # Sensitive or high-churn files
23 | .idea/**/dataSources/
24 | .idea/**/dataSources.ids
25 | .idea/**/dataSources.local.xml
26 | .idea/**/sqlDataSources.xml
27 | .idea/**/dynamic.xml
28 | .idea/**/uiDesigner.xml
29 | .idea/**/dbnavigator.xml
30 |
31 | # Gradle
32 | .idea/**/gradle.xml
33 | .idea/**/libraries
34 |
35 | # Gradle and Maven with auto-import
36 | # When using Gradle or Maven with auto-import, you should exclude module files,
37 | # since they will be recreated, and may cause churn. Uncomment if using
38 | # auto-import.
39 | # .idea/artifacts
40 | # .idea/compiler.xml
41 | # .idea/jarRepositories.xml
42 | # .idea/modules.xml
43 | # .idea/*.iml
44 | # .idea/modules
45 | # *.iml
46 | # *.ipr
47 |
48 | # CMake
49 | cmake-build-*/
50 |
51 | # Mongo Explorer plugin
52 | .idea/**/mongoSettings.xml
53 |
54 | # File-based project format
55 | *.iws
56 |
57 | # IntelliJ
58 | out/
59 |
60 | # mpeltonen/sbt-idea plugin
61 | .idea_modules/
62 |
63 | # JIRA plugin
64 | atlassian-ide-plugin.xml
65 |
66 | # Cursive Clojure plugin
67 | .idea/replstate.xml
68 |
69 | # Crashlytics plugin (for Android Studio and IntelliJ)
70 | com_crashlytics_export_strings.xml
71 | crashlytics.properties
72 | crashlytics-build.properties
73 | fabric.properties
74 |
75 | # Editor-based Rest Client
76 | .idea/httpRequests
77 |
78 | # Android studio 3.1+ serialized cache file
79 | .idea/caches/build_file_checksums.ser
80 |
81 | ### Intellij+all Patch ###
82 | # Ignores the whole .idea folder and all .iml files
83 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
84 |
85 | .idea/
86 |
87 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
88 |
89 | *.iml
90 | modules.xml
91 | .idea/misc.xml
92 | *.ipr
93 |
94 | # Sonarlint plugin
95 | .idea/sonarlint
96 |
97 | ### Java ###
98 | # Compiled class file
99 | *.class
100 |
101 | # Log file
102 | *.log
103 |
104 | # BlueJ files
105 | *.ctxt
106 |
107 | # Mobile Tools for Java (J2ME)
108 | .mtj.tmp/
109 |
110 | # Package Files #
111 | *.jar
112 | *.war
113 | *.nar
114 | *.ear
115 | *.zip
116 | *.tar.gz
117 | *.rar
118 |
119 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
120 | hs_err_pid*
121 |
122 | ### macOS ###
123 | # General
124 | .DS_Store
125 | .AppleDouble
126 | .LSOverride
127 |
128 | # Icon must end with two \r
129 | Icon
130 |
131 |
132 | # Thumbnails
133 | ._*
134 |
135 | # Files that might appear in the root of a volume
136 | .DocumentRevisions-V100
137 | .fseventsd
138 | .Spotlight-V100
139 | .TemporaryItems
140 | .Trashes
141 | .VolumeIcon.icns
142 | .com.apple.timemachine.donotpresent
143 |
144 | # Directories potentially created on remote AFP share
145 | .AppleDB
146 | .AppleDesktop
147 | Network Trash Folder
148 | Temporary Items
149 | .apdisk
150 |
151 | ### Maven ###
152 | target/
153 | pom.xml.tag
154 | pom.xml.releaseBackup
155 | pom.xml.versionsBackup
156 | pom.xml.next
157 | release.properties
158 | dependency-reduced-pom.xml
159 | buildNumber.properties
160 | .mvn/timing.properties
161 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar
162 | .mvn/wrapper/maven-wrapper.jar
163 |
164 | ### Maven Patch ###
165 | # Eclipse m2e generated files
166 | # Eclipse Core
167 | .project
168 | # JDT-specific (Eclipse Java Development Tools)
169 | .classpath
170 |
171 | # End of https://www.toptal.com/developers/gitignore/api/java,intellij+all,macos,maven
172 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # What is CloudAC
2 | CloudAC is a proof of concept, micro Minecraft anti-cheat system that fully performs all its checks and data processing on a separate program that can be installed on a different machine to truly remove all the performance impact of the checks and data processors (Which are the heaviest parts of an anti-cheat) from the Minecraft-server itself, the only anti-cheat related actions that are actually performed by the Minecraft-server's resources is sending all the relevant packets data to the Computation server and the punishment system.
3 |
4 | ### Why
5 | CloudAC shows an idea that would work to actually completely solve one of the biggest problems of server-sided Minecraft anti-cheats, agree or not any anti-cheat even with the best optimizations and most elegant source code that's built to prevent most or all the game-breaking cheats in Minecraft will take significantly more resources than your average plugin, sometimes in more severe cases, the anti-cheat will improve your player's experience by banning cheaters but will also degrade it because of lag caused by it.
6 |
7 | ### Technical details
8 | CloudAC's current design has two parts, the ACTransmitter and the ComputationServer, the ACTransmitter sends all the required data to the ComputationServer as soon as it arrived and the ComputationServer processes this data and uses it to run its checks then sends the results of these checks back to the ACTransmitter where it's used in the punishment system, the computation server always tracks what happens on the server and uses most of the design choices and tactics that are already used by any traditional anti-cheat, keep in mind that this explanation is simplified.
9 |
10 | #### Technical details - More choices
11 | Another advantage of having the ComputationServer as a separate program is that we can program it in whatever programming language we want, in this case, I used Go because it is compiled, modern, a little faster than java, and is functional oriented but still has stuff like interfaces so you can still kind of re-create your anti-cheat polymorphic design even though the language is functionaly oriented, and I already used it before, however in theory you can write it really in whatever language you want, another good choice would be Rust since its modern has a big amount of features and its great performance.
12 |
13 | ### What about the latency
14 | In CloudAC's case, the latency of sending the packets data to the Computation program using sockets is not much of a problem as we are going for a silent anti-cheat design, there are two ways to configure an anti-cheat to operate depending on what your priority is, banning the cheater, or preventing the cheat, if your priority is to ban them, its better to not let the cheater know if he is being detected by setting him back, it's better to "keep them in the dark" and let them cheat until your anti-cheat has enough data to ban them, this is the tactic most bigger servers use and is the one we chose to go with for CloudAC.
15 |
16 | ### Contributing
17 | CloudAC is a prototype meant to show how designing this kind of system could work and was never meant to be anything more than that, however we are open-minded and while without dedicated development it would probably never become a production ready anti-cheat we do welcome any contributions that come to expand and improve the code base which will provide a better example for the community.
18 |
19 | If you are interested in helping us continute and improve CloudAC,
20 | here our current ToDo list:
21 | - Upgrade the sockets code to use a secure encrypted connection with TLS
22 | - Improve data processing to be dynamic and not need to check packet type
23 | - Add more checks and increase data processing
24 | - Your suggestions and ideas
25 |
26 | ### Disclaimer
27 | I didn't invent the idea of running the brain of your anti-cheat separately from your Minecraft-server itself, that idea existed for some time and is/was used by a few big servers, the idea of CloudAC is to make it more widespread and known to the public and hopefully inspire future projects to use this superior design and by that hopefully improve the anticheating solutions that are coming out there.
28 |
29 | #### Disclaimer - current code state
30 | The current code was written pretty swiftly and was bodged together to some extent since originally I didn't plan on publishing it, it was meant to be more of a proof of concept attempt, which is why some parts might be a bit wack, I did and will introduce more clean up and comments but I believe it is decent already and can definitely be used as a nice base, however, feel free to implement any changes or improvements you believe fit.
31 |
32 |
33 | 
34 |
--------------------------------------------------------------------------------
/ACTransmitter/src/main/java/com/nort721/transmitter/listeners/PacketsListener.java:
--------------------------------------------------------------------------------
1 | package com.nort721.transmitter.listeners;
2 |
3 | import com.comphenix.protocol.PacketType;
4 | import com.comphenix.protocol.ProtocolLibrary;
5 | import com.comphenix.protocol.events.ListenerPriority;
6 | import com.comphenix.protocol.events.PacketAdapter;
7 | import com.comphenix.protocol.events.PacketEvent;
8 | import com.comphenix.protocol.injector.server.TemporaryPlayer;
9 | import com.nort721.transmitter.ACTransmitter;
10 | import com.nort721.transmitter.utils.wrappers.WrapperPlayClientFlying;
11 | import org.bukkit.entity.Player;
12 |
13 | import java.util.Iterator;
14 | import java.util.List;
15 | import java.util.Spliterator;
16 | import java.util.Spliterators;
17 | import java.util.stream.Collectors;
18 | import java.util.stream.StreamSupport;
19 |
20 | public class PacketsListener extends PacketAdapter {
21 |
22 | private final ACTransmitter acTransmitter;
23 |
24 | public PacketsListener(ACTransmitter acTransmitter) {
25 | super(ACTransmitter.getInstance(), ListenerPriority.LOWEST, getSupportedPacketTypes());
26 | ProtocolLibrary.getProtocolManager().addPacketListener(this);
27 | this.acTransmitter = acTransmitter;
28 | }
29 |
30 | @Override
31 | public void onPacketReceiving(PacketEvent event) {
32 | Player player = event.getPlayer();
33 |
34 | if (player instanceof TemporaryPlayer) return;
35 |
36 | long currentTime = System.currentTimeMillis();
37 |
38 | // ToDo send packets values dynamically without checking types
39 |
40 | StringBuilder packetData = new StringBuilder();
41 |
42 | if (event.getPacketType() == PacketType.Play.Client.FLYING ||
43 | event.getPacketType() == PacketType.Play.Client.POSITION ||
44 | event.getPacketType() == PacketType.Play.Client.POSITION_LOOK ||
45 | event.getPacketType() == PacketType.Play.Client.LOOK) {
46 |
47 | WrapperPlayClientFlying flying = new WrapperPlayClientFlying(event);
48 |
49 | packetData.append("2").append("|");
50 | packetData.append(player.getUniqueId()).append("|");
51 | packetData.append(currentTime).append('|');
52 | packetData.append(flying.hasPosition()).append('|');
53 | packetData.append(flying.hasLook()).append('|');
54 | packetData.append(flying.getOnGround()).append('|');
55 | packetData.append(flying.getX()).append('|');
56 | packetData.append(flying.getY()).append('|');
57 | packetData.append(flying.getZ()).append('|');
58 | packetData.append(flying.getYaw()).append('|');
59 | packetData.append(flying.getPitch());
60 |
61 | } else if (event.getPacketType() == PacketType.Play.Client.ABILITIES) {
62 |
63 | boolean isFlying = event.getPacket().getBooleans().read(1);
64 | boolean canFly = event.getPacket().getBooleans().read(2);
65 |
66 | packetData.append("3").append("|");
67 | packetData.append(player.getUniqueId()).append("|");
68 | packetData.append(currentTime).append('|');
69 | packetData.append(isFlying).append('|');
70 | packetData.append(canFly);
71 | }
72 |
73 | if (packetData.length() > 0) {
74 | acTransmitter.getComputationServerSender().sendDataToServer(packetData.toString());
75 | }
76 | }
77 |
78 | @Override
79 | public void onPacketSending(PacketEvent event) {
80 | Player player = event.getPlayer();
81 |
82 | if (player instanceof TemporaryPlayer) return;
83 |
84 | long currentTime = System.currentTimeMillis();
85 |
86 | // ToDo send packets values dynamically without checking types
87 |
88 | StringBuilder packetData = new StringBuilder();
89 |
90 | if (event.getPacketType() == PacketType.Play.Server.LOGIN) {
91 |
92 | packetData.append("0").append("|");
93 | packetData.append(player.getUniqueId()).append("|");
94 | packetData.append(currentTime);
95 |
96 | } else if (event.getPacketType() == PacketType.Play.Server.ABILITIES) {
97 |
98 | boolean isFlying = event.getPacket().getBooleans().read(1);
99 | boolean canFly = event.getPacket().getBooleans().read(2);
100 |
101 | packetData.append("4").append("|");
102 | packetData.append(player.getUniqueId()).append("|");
103 | packetData.append(currentTime).append('|');
104 | packetData.append(isFlying).append('|');
105 | packetData.append(canFly);
106 | }
107 |
108 | if (packetData.length() > 0) {
109 | acTransmitter.getComputationServerSender().sendDataToServer(packetData.toString());
110 | }
111 | }
112 |
113 | /**
114 | * @return - All supported Packet Types for the server's corresponding version
115 | * (Earlier and later versions may contain packets that have not been implemented to the server's version)
116 | *
117 | * I also hate how it has to be static. Thanks ProtocolLib!
118 | */
119 | private static Iterable getSupportedPacketTypes() {
120 | final Iterator packetTypeIterator = PacketType.values().iterator();
121 |
122 | List packets = StreamSupport.stream(Spliterators.spliteratorUnknownSize(packetTypeIterator, Spliterator.ORDERED), false)
123 | .filter(PacketType::isSupported)
124 | .collect(Collectors.toList());
125 |
126 | // fix for red server ping in server menu
127 | packets.remove(PacketType.Status.Server.PONG);
128 |
129 | // No need to run this in parallel. Will only be called once upon server start.
130 | return packets;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------