├── docker ├── build_ubuntu-20.04 │ ├── docker-entrypoint.sh │ ├── README.md │ └── Dockerfile ├── build_ubuntu-22.04 │ ├── docker-entrypoint.sh │ ├── README.md │ └── Dockerfile ├── build_ubuntu-18.04 │ ├── README.md │ ├── docker-entrypoint.sh │ └── Dockerfile └── build.sh ├── .gitmodules ├── CMakeLists.txt ├── main.cpp ├── api.hpp ├── api.cpp ├── weather-extension.cpp ├── weather-extension.hpp ├── weather-region.cpp ├── test.pwn ├── README.md ├── weather-region.hpp ├── natives.hpp ├── interface.hpp ├── weather-component.hpp ├── natives.cpp ├── .clang-format ├── .gitignore ├── real-world-weather.inc ├── weather-component.cpp └── LICENSE.md /docker/build_ubuntu-20.04/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -z $CONFIG ] && config=Release || config="$CONFIG" 3 | 4 | cmake \ 5 | -S . \ 6 | -B build \ 7 | -G Ninja \ 8 | -DCMAKE_C_FLAGS=-m32 \ 9 | -DCMAKE_CXX_FLAGS=-m32 \ 10 | -DCMAKE_BUILD_TYPE=$config \ 11 | && 12 | cmake \ 13 | --build build \ 14 | --config $config \ 15 | --parallel $(nproc) 16 | -------------------------------------------------------------------------------- /docker/build_ubuntu-22.04/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -z $CONFIG ] && config=Release || config="$CONFIG" 3 | 4 | cmake \ 5 | -S . \ 6 | -B build \ 7 | -G Ninja \ 8 | -DCMAKE_C_FLAGS=-m32 \ 9 | -DCMAKE_CXX_FLAGS=-m32 \ 10 | -DCMAKE_BUILD_TYPE=$config \ 11 | && 12 | cmake \ 13 | --build build \ 14 | --config $config \ 15 | --parallel $(nproc) 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sdk"] 2 | path = sdk 3 | url = https://github.com/openmultiplayer/open.mp-sdk 4 | [submodule "network"] 5 | path = network 6 | url = https://github.com/openmultiplayer/open.mp-network 7 | [submodule "pawn-natives"] 8 | path = pawn-natives 9 | url = https://github.com/openmultiplayer/pawn-natives 10 | [submodule "pawn"] 11 | path = pawn 12 | url = https://github.com/openmultiplayer/compiler 13 | -------------------------------------------------------------------------------- /docker/build_ubuntu-18.04/README.md: -------------------------------------------------------------------------------- 1 | open.mp Linux build image 2 | ========================= 3 | 4 | How to use: 5 | 6 | 1. `docker build -t open.mp/build:ubuntu-18.04 .` 7 | 1. `docker run --rm -ti -v /path/to/omp/sources:/omp -w /omp open.mp/build:ubuntu-18.04` 8 | 1. ??? 9 | 1. Profit! Built open.mp is available in /path/to/omp/sources/build 10 | 1. Note: You can use `-e CONFIG=Debug` or `-e CONFIG=RelWithDebInfo` in the `docker run` call to change the build type 11 | -------------------------------------------------------------------------------- /docker/build_ubuntu-20.04/README.md: -------------------------------------------------------------------------------- 1 | open.mp Linux build image 2 | ========================= 3 | 4 | How to use: 5 | 6 | 1. `docker build -t open.mp/build:ubuntu-20.04 .` 7 | 1. `docker run --rm -ti -v /path/to/omp/sources:/omp -w /omp open.mp/build:ubuntu-20.04` 8 | 1. ??? 9 | 1. Profit! Built open.mp is available in /path/to/omp/sources/build 10 | 1. Note: You can use `-e CONFIG=Debug` or `-e CONFIG=RelWithDebInfo` in the `docker run` call to change the build type 11 | -------------------------------------------------------------------------------- /docker/build_ubuntu-22.04/README.md: -------------------------------------------------------------------------------- 1 | open.mp Linux build image 2 | ========================= 3 | 4 | How to use: 5 | 6 | 1. `docker build -t open.mp/build:ubuntu-22.04 .` 7 | 1. `docker run --rm -ti -v /path/to/omp/sources:/omp -w /omp open.mp/build:ubuntu-22.04` 8 | 1. ??? 9 | 1. Profit! Built open.mp is available in /path/to/omp/sources/build 10 | 1. Note: You can use `-e CONFIG=Debug` or `-e CONFIG=RelWithDebInfo` in the `docker run` call to change the build type 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(full-template LANGUAGES C CXX VERSION 0.0.1) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_subdirectory(sdk) 7 | add_subdirectory(network) 8 | 9 | include_directories( 10 | . 11 | pawn/source 12 | pawn/source/linux 13 | ) 14 | 15 | add_definitions( 16 | -DHAVE_STDINT_H=1 17 | -DPAWN_CELL_SIZE=32 18 | ) 19 | 20 | add_library(${PROJECT_NAME} SHARED 21 | api.cpp 22 | main.cpp 23 | natives.cpp 24 | weather-component.cpp 25 | weather-extension.cpp 26 | weather-region.cpp 27 | ) 28 | 29 | target_link_libraries(${PROJECT_NAME} PRIVATE 30 | OMP-SDK 31 | ) 32 | 33 | -------------------------------------------------------------------------------- /docker/build_ubuntu-22.04/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | RUN \ 3 | dpkg --add-architecture i386 && \ 4 | apt-get update && \ 5 | apt-get install -y \ 6 | cmake \ 7 | ninja-build \ 8 | clang-11 \ 9 | python3-pip \ 10 | gcc-9-multilib \ 11 | g++-9-multilib \ 12 | libstdc++-11-dev:i386 \ 13 | && \ 14 | useradd -m user && \ 15 | su user -c 'pip3 install --user conan' 16 | 17 | USER user 18 | 19 | ENV CC=/usr/bin/clang-11 \ 20 | CXX=/usr/bin/clang++-11 \ 21 | PATH=~/.local/bin:${PATH} 22 | 23 | COPY docker-entrypoint.sh / 24 | CMD /docker-entrypoint.sh 25 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2022, open.mp team and contributors. 7 | */ 8 | 9 | // Required for most of open.mp. 10 | #include 11 | 12 | // Include the globally shared definitions for this component. 13 | #include "interface.hpp" 14 | 15 | // Include the binary-local implementation for this component. 16 | #include "weather-component.hpp" 17 | 18 | // Automatically called when the compiled binary is loaded. 19 | COMPONENT_ENTRY_POINT() 20 | { 21 | return WeatherComponent::getInstance(); 22 | } 23 | -------------------------------------------------------------------------------- /docker/build_ubuntu-18.04/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -z $CONFIG ] && config=Release || config="$CONFIG" 3 | [ -z $BUILD_SHARED ] && build_shared=1 || build_shared="$BUILD_SHARED" 4 | [ -z $BUILD_SERVER ] && build_server=1 || build_server="$BUILD_SERVER" 5 | [ -z $BUILD_TOOLS ] && build_tools=0 || build_tools="$BUILD_TOOLS" 6 | 7 | cmake \ 8 | -S . \ 9 | -B build \ 10 | -G Ninja \ 11 | -DCMAKE_C_FLAGS=-m32 \ 12 | -DCMAKE_CXX_FLAGS=-m32 \ 13 | -DCMAKE_BUILD_TYPE=$config \ 14 | -DSHARED_OPENSSL=$build_shared \ 15 | -DSTATIC_STDCXX=true \ 16 | -DBUILD_SERVER=$build_server \ 17 | -DBUILD_ABI_CHECK_TOOL=$build_tools \ 18 | && 19 | cmake \ 20 | --build build \ 21 | --config $config \ 22 | --parallel $(nproc) 23 | -------------------------------------------------------------------------------- /api.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This Source Code Form is subject to the terms of the Mozilla Public License, 5 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 6 | * obtain one at http://mozilla.org/MPL/2.0/. 7 | * 8 | * The original code is copyright (c) 2022, open.mp team and contributors. 9 | */ 10 | 11 | #include 12 | 13 | // This is just a placeholder for some real world weather lookup API. We aren't going to bother 14 | // with a full implementation as this class merely serves as an example of real-world usage. It 15 | // isn't important to demonstrating the open.mp component SDK. 16 | class SomeExternalAPI 17 | { 18 | private: 19 | // 10 possibilities: 20 | int currentWeather_ = 0; 21 | 22 | public: 23 | // Initialise this API to find the weather in a real-world location. 24 | SomeExternalAPI(std::string location); 25 | 26 | // Not `const` because we may get a new weather. 27 | int getCurrentWeather(); 28 | }; 29 | -------------------------------------------------------------------------------- /api.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2022, open.mp team and contributors. 7 | */ 8 | 9 | #include 10 | 11 | #include "api.hpp" 12 | 13 | SomeExternalAPI::SomeExternalAPI(std::string) 14 | { 15 | // We don't actually care about the location for this example... 16 | } 17 | 18 | // This is just a placeholder for some real world weather lookup API. We aren't going to bother 19 | // with a full implementation as this class merely serves as an example of real-world usage. It 20 | // isn't important to demonstrating the open.mp component SDK. 21 | int SomeExternalAPI::getCurrentWeather() 22 | { 23 | // 1% chance of randomly selecting a new weather. 24 | if (rand() % 100 == 0) 25 | { 26 | // I'm not using ``... 27 | currentWeather_ = rand() % 10; 28 | } 29 | return currentWeather_; 30 | } 31 | -------------------------------------------------------------------------------- /weather-extension.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2022, open.mp team and contributors. 7 | */ 8 | 9 | // This is the private implementation of the public interface. We must know the interface. 10 | #include "weather-extension.hpp" 11 | 12 | // Implementations of the various methods from the public API. 13 | IWeatherRegion* WeatherExtension::getWeatherRegion() 14 | { 15 | // Get the player's current weather region. 16 | return region_; 17 | } 18 | 19 | void WeatherExtension::setWeatherRegion(IWeatherRegion* region) 20 | { 21 | // Get the player's current weather region. 22 | region_ = region; 23 | } 24 | 25 | // Required extension methods. 26 | void WeatherExtension::freeExtension() 27 | { 28 | // Delete this extension. 29 | delete this; 30 | } 31 | 32 | void WeatherExtension::reset() 33 | { 34 | // Reset data when the main mode changes. 35 | region_ = nullptr; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /docker/build_ubuntu-20.04/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | RUN \ 3 | dpkg --add-architecture i386 && \ 4 | apt-get update && \ 5 | apt-get install -y \ 6 | gpg \ 7 | wget \ 8 | && \ 9 | wget -O- https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | \ 10 | gpg --dearmor - | \ 11 | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null && \ 12 | echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | \ 13 | tee /etc/apt/sources.list.d/kitware.list >/dev/null && \ 14 | apt-get update && \ 15 | apt-get install -y \ 16 | cmake \ 17 | ninja-build \ 18 | clang-10 \ 19 | python3-pip \ 20 | gcc-9-multilib \ 21 | g++-9-multilib \ 22 | libstdc++-10-dev:i386 \ 23 | && \ 24 | useradd -m user && \ 25 | su user -c 'pip3 install --user conan' 26 | 27 | USER user 28 | 29 | ENV CC=/usr/bin/clang-10 \ 30 | CXX=/usr/bin/clang++-10 \ 31 | PATH=~/.local/bin:${PATH} 32 | 33 | COPY docker-entrypoint.sh / 34 | CMD /docker-entrypoint.sh 35 | -------------------------------------------------------------------------------- /docker/build_ubuntu-18.04/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN \ 3 | dpkg --add-architecture i386 && \ 4 | apt-get update && \ 5 | apt-get install -y \ 6 | gpg \ 7 | wget \ 8 | && \ 9 | wget -O- https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | \ 10 | gpg --dearmor - | \ 11 | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null && \ 12 | echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | \ 13 | tee /etc/apt/sources.list.d/kitware.list >/dev/null && \ 14 | apt-get update && \ 15 | apt-get install -y \ 16 | cmake \ 17 | ninja-build \ 18 | clang-10 \ 19 | python3-pip \ 20 | gcc-8-multilib \ 21 | g++-8-multilib \ 22 | libstdc++6:i386 \ 23 | libc6:i386 \ 24 | && \ 25 | useradd -m user && \ 26 | su user -c 'pip3 install --user conan' 27 | 28 | USER user 29 | 30 | ENV CC=/usr/bin/clang-10 \ 31 | CXX=/usr/bin/clang++-10 \ 32 | PATH=~/.local/bin:${PATH} 33 | 34 | COPY docker-entrypoint.sh / 35 | CMD /docker-entrypoint.sh 36 | -------------------------------------------------------------------------------- /weather-extension.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This Source Code Form is subject to the terms of the Mozilla Public License, 5 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 6 | * obtain one at http://mozilla.org/MPL/2.0/. 7 | * 8 | * The original code is copyright (c) 2022, open.mp team and contributors. 9 | */ 10 | 11 | // Required for most of open.mp. 12 | #include 13 | 14 | // This is the private implementation of the public interface. We must know the interface. 15 | #include "interface.hpp" 16 | 17 | // Import open.mp structures that aren't ABI safe. 18 | using namespace Impl; 19 | 20 | // `final` so we don't need virtual destructors. Also because we know it isn't inherited. 21 | class WeatherExtension final 22 | // This class is an implementation of the publicly shared `IWeatherExtension` interface. 23 | : public IWeatherExtension 24 | { 25 | private: 26 | IWeatherRegion* region_; 27 | 28 | public: 29 | // Implementations of the various methods from the public API. 30 | IWeatherRegion* getWeatherRegion() override; 31 | 32 | void setWeatherRegion(IWeatherRegion* region) override; 33 | 34 | // Required extension methods. 35 | void freeExtension() override; 36 | 37 | void reset() override; 38 | 39 | // Component-private methods (internal methods) go here. 40 | }; 41 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Available configs: Debug, [RelWithDebInfo], Release 4 | [[ -z "$CONFIG" ]] \ 5 | && config=RelWithDebInfo \ 6 | || config="$CONFIG" 7 | # Available versions: 18.04, [20.04], 22.04 8 | [[ -z "$UBUNTU_VERSION" ]] \ 9 | && ubuntu_version=20.04 \ 10 | || ubuntu_version="$UBUNTU_VERSION" 11 | # Available options: [true], false 12 | [[ -z "$BUILD_SHARED" ]] \ 13 | && build_shared=1 \ 14 | || build_shared="$BUILD_SHARED" 15 | # Available options: [true], false 16 | [[ -z "$BUILD_SERVER" ]] \ 17 | && build_server=1 \ 18 | || build_server="$BUILD_SERVER" 19 | # Available options: true, [false] 20 | [[ -z "$BUILD_TOOLS" ]] \ 21 | && build_tools=0 \ 22 | || build_tools="$BUILD_TOOLS" 23 | 24 | docker build \ 25 | -t open.mp/build:ubuntu-${ubuntu_version} \ 26 | build_ubuntu-${ubuntu_version}/ \ 27 | || exit 1 28 | 29 | folders=('build' 'conan') 30 | for folder in "${folders[@]}"; do 31 | if [[ ! -d "./${folder}" ]]; then 32 | mkdir ${folder} && 33 | chown 1000:1000 ${folder} || exit 1 34 | fi 35 | done 36 | 37 | docker run \ 38 | --rm \ 39 | -t \ 40 | -w /code \ 41 | -v $PWD/..:/code \ 42 | -v $PWD/build:/code/build \ 43 | -v $PWD/conan:/home/user/.conan \ 44 | -e CONFIG=${config} \ 45 | -e BUILD_SHARED=${build_shared} \ 46 | -e BUILD_SERVER=${build_server} \ 47 | -e BUILD_TOOLS=${build_tools} \ 48 | -e OMP_BUILD_VERSION=$(git rev-list $(git rev-list --max-parents=0 HEAD) HEAD | wc -l) \ 49 | -e OMP_BUILD_COMMIT=$(git rev-parse HEAD) \ 50 | open.mp/build:ubuntu-${ubuntu_version} 51 | -------------------------------------------------------------------------------- /weather-region.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2022, open.mp team and contributors. 7 | */ 8 | 9 | // This is the private implementation of the public interface. We must know the interface. 10 | #include "weather-region.hpp" 11 | 12 | // Import open.mp structures that aren't ABI safe. 13 | using namespace Impl; 14 | 15 | // Implementations of the various methods from the public API. 16 | StringView WeatherRegion::getName() const 17 | { 18 | return name_; 19 | } 20 | 21 | StringView WeatherRegion::getLocation() const 22 | { 23 | return location_; 24 | } 25 | 26 | bool WeatherRegion::updateWeather() 27 | { 28 | // Call the API to get the latest weather in this region. 29 | int weather = api_.getCurrentWeather(); 30 | 31 | // Has the weather changed? 32 | if (weather != currentWeather_) 33 | { 34 | // Yes, record the new one. 35 | currentWeather_ = weather; 36 | return true; 37 | } 38 | return false; 39 | } 40 | 41 | E_WEATHER WeatherRegion::getWeather() const 42 | { 43 | // Convert the weather type retreived from the real world weather API. 44 | switch (currentWeather_) 45 | { 46 | case 0: 47 | return E_WEATHER::SUNNY; 48 | case 1: 49 | return E_WEATHER::WINDY; 50 | case 2: 51 | return E_WEATHER::STORMY; 52 | case 3: 53 | return E_WEATHER::SNOWING; 54 | case 4: 55 | return E_WEATHER::HOT; 56 | case 5: 57 | return E_WEATHER::SLEET; 58 | case 6: 59 | return E_WEATHER::CLOUDY; 60 | case 7: 61 | return E_WEATHER::RAINING; 62 | case 8: 63 | return E_WEATHER::DRIZZLING; 64 | case 9: 65 | return E_WEATHER::FOGGY; 66 | } 67 | return E_WEATHER::UNKNOWN; 68 | } 69 | 70 | int WeatherRegion::getID() const 71 | { 72 | // The pool ID is set automatically in `PoolIDProvider`. 73 | return poolID; 74 | } 75 | 76 | // More methods to be used only in this component (internal methods). Implementation details. 77 | WeatherRegion::WeatherRegion(StringView name, StringView location) 78 | : api_(location.to_string()) 79 | , currentWeather_(0) 80 | , name_(name) 81 | , location_(location) 82 | { 83 | } 84 | -------------------------------------------------------------------------------- /test.pwn: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | new RWW:gRegionLV; 5 | new RWW:gRegionLS; 6 | new RWW:gRegionSF; 7 | 8 | public OnFilterScriptInit() 9 | { 10 | gRegionLV = RWW_Create("Las Venturas", "America/Las Vegas"); 11 | if (RWW_IsValid(gRegionLV)) 12 | { 13 | new name[32], location[32]; 14 | RWW_GetName(gRegionLV, name); 15 | RWW_GetLocation(gRegionLV, location); 16 | printf("%d = %s (%s)", _:gRegionLV, name, location); 17 | } 18 | else 19 | { 20 | printf("Failed to create LV region"); 21 | } 22 | if (!(gRegionLS = RWW_Create("Los Santos", "America/Los Angeles"))) 23 | { 24 | printf("Failed to create LV region"); 25 | } 26 | gRegionSF = RWW_Create("San Fierro", "America/San Fransisco"); 27 | if (gRegionSF == INVALID_RWW_REGION) 28 | { 29 | printf("Failed to create SF region"); 30 | } 31 | 32 | return 1; 33 | } 34 | 35 | public OnFilterScriptExit() 36 | { 37 | RWW_Destroy(gRegionLV); 38 | RWW_Destroy(gRegionLS); 39 | RWW_Destroy(gRegionSF); 40 | return 1; 41 | } 42 | 43 | SetPlayerRealWeather(playerid, E_WEATHER:weather) 44 | { 45 | switch (weather) 46 | { 47 | case E_WEATHER_SUNNY, E_WEATHER_HOT: 48 | SetPlayerWeather(playerid, 11); 49 | case E_WEATHER_RAINING, E_WEATHER_STORMY, E_WEATHER_DRIZZLING: 50 | SetPlayerWeather(playerid, 8); 51 | case E_WEATHER_WINDY, E_WEATHER_CLOUDY, E_WEATHER_FOGGY: 52 | SetPlayerWeather(playerid, 12); 53 | case E_WEATHER_SNOWING, E_WEATHER_SLEET: 54 | SetPlayerWeather(playerid, 19); 55 | default: 56 | return; 57 | } 58 | } 59 | 60 | DeterminePlayerRegion(playerid) 61 | { 62 | // Somehow. Doesn't matter. 63 | switch (random(3)) 64 | { 65 | case 0: 66 | RWW_SetPlayerRegion(playerid, gRegionLV); 67 | case 1: 68 | RWW_SetPlayerRegion(playerid, gRegionLS); 69 | case 2: 70 | RWW_SetPlayerRegion(playerid, gRegionSF); 71 | } 72 | } 73 | 74 | public OnPlayerSpawn(playerid) 75 | { 76 | DeterminePlayerRegion(playerid); 77 | SetPlayerRealWeather(playerid, RWW_GetWeather(RWW_GetPlayerRegion(playerid))); 78 | return 0; 79 | } 80 | 81 | public OnWeatherChange(RWW:region, E_WEATHER:previous, E_WEATHER:current) 82 | { 83 | new name[32], from[32], to[32]; 84 | RWW_GetName(region, name); 85 | RWW_GetDescription(previous, from); 86 | RWW_GetDescription(current, to); 87 | printf("Region %s changed weather from %s to %s", name, from, to); 88 | return 1; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | open.mp Full Component Template 2 | ================================= 3 | 4 | This is a more in complete component start point template. It demonstrates how to declare a component that other components can call, has events they can subscribe to, and a pawn scripting API. 5 | 6 | ## UID 7 | 8 | Since this is a template, i.e. a start point for new components, it needs a Unique ID adding. Don't forget to get a new one from here: 9 | 10 | https://open.mp/uid 11 | 12 | ## Required Tools 13 | 14 | * [CMake 3.19+](https://cmake.org/) 15 | * [Conan 1.53+](https://conan.io/) 16 | * [Visual Studio 2019+](https://www.visualstudio.com/) (on Windows) 17 | * Clang (on Linux) 18 | 19 | Visual Studio needs the `Desktop development with C++` workload with the `MSVC v142`, `Windows 10 SDK`, and `C++ Clang tools for Windows` components. 20 | 21 | ## Sources 22 | 23 | ```bash 24 | # With HTTPS: 25 | git clone --recursive https://github.com/openmultiplayer/full-template 26 | # With SSH: 27 | git clone --recursive git@github.com:openmultiplayer/full-template 28 | ``` 29 | 30 | Note the use of the `--recursive` argument, because this repository contains submodules. A useful setting when cloning recursive repos is: 31 | 32 | ```bash 33 | git config --global url."git@github.com:".insteadOf "https://github.com/" 34 | ``` 35 | 36 | Which allows you to push `https://` repos you have permissions on. 37 | 38 | ## Building on Windows 39 | 40 | ```bash 41 | mkdir build 42 | cd build 43 | cmake .. -A Win32 -T ClangCL 44 | ``` 45 | 46 | Open Visual Studio and build the solution. 47 | 48 | ## Building on Linux 49 | 50 | ```bash 51 | mkdir build 52 | cd build 53 | # May need to configure this line. 54 | export CC=/usr/lib/llvm/13/bin/clang CXX=/usr/lib/llvm/13/bin/clang++ 55 | cmake .. -G Ninja -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_BUILD_TYPE=Debug \ 56 | cmake --build . --config Debug 57 | ``` 58 | 59 | Change `Debug` to `Release` for final versions. 60 | 61 | ## Building with Docker 62 | 63 | ```bash 64 | cd docker 65 | .\build.sh 66 | ``` 67 | 68 | You may need to set up some directories first: 69 | 70 | ```bash 71 | mkdir build 72 | mkdir conan 73 | sudo chown 1000 build 74 | sudo chown 1000 conan 75 | ``` 76 | 77 | Instead you run the script as root, and target a specific distro: 78 | 79 | ```bash 80 | UBUNTU_VERSION=18.04 sudo .\build.sh 81 | ``` 82 | 83 | The output is in `docker/build/` 84 | 85 | -------------------------------------------------------------------------------- /weather-region.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This Source Code Form is subject to the terms of the Mozilla Public License, 5 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 6 | * obtain one at http://mozilla.org/MPL/2.0/. 7 | * 8 | * The original code is copyright (c) 2022, open.mp team and contributors. 9 | */ 10 | 11 | // Required for most of open.mp. 12 | #include 13 | 14 | // Get pool ID information. 15 | #include 16 | 17 | // This is the private implementation of the public interface. We must know the interface. 18 | #include "interface.hpp" 19 | 20 | // This entity holds server data, but must use an external service for weather reporting. 21 | #include "api.hpp" 22 | 23 | // Import open.mp structures that aren't ABI safe. 24 | using namespace Impl; 25 | 26 | // `final` so we don't need virtual destructors. Also because we know it isn't inherited. 27 | class WeatherRegion final 28 | // This class is an implementation of the publicly shared `IWeatherRegion` interface. 29 | : public IWeatherRegion 30 | // This is stored in a pool, so needs a standard pool ID. 31 | , public PoolIDProvider 32 | // Ensure this entity can't be copied without our help. 33 | , public NoCopy 34 | { 35 | private: 36 | // An interface to some immaginary weather lookup system. Web API etc. 37 | SomeExternalAPI api_; 38 | 39 | // The last weather loaded from the API, in the API format. 40 | int currentWeather_; 41 | 42 | // The name of this small area of localised weather. 43 | String const name_; 44 | 45 | // The location of this small area of localised weather. 46 | String const location_; 47 | 48 | public: 49 | // Implementations of the various methods from the public API. 50 | StringView getName() const override; 51 | 52 | // Get the location. Public APIs use `StringView` because it is ABI stable. 53 | StringView getLocation() const override; 54 | 55 | // Convert from the API-specific weather format to the component's global format. 56 | E_WEATHER getWeather() const override; 57 | 58 | // Required by anything that is `PoolIDProvider`. 59 | int getID() const override; 60 | 61 | // More methods to be used only in this component (internal methods). Implementation details. 62 | WeatherRegion(StringView name, StringView location); 63 | 64 | // Only this component should update weather, so don't expose this method. 65 | bool updateWeather(); 66 | }; 67 | -------------------------------------------------------------------------------- /natives.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This Source Code Form is subject to the terms of the Mozilla Public License, 5 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 6 | * obtain one at http://mozilla.org/MPL/2.0/. 7 | * 8 | * The original code is copyright (c) 2022, open.mp team and contributors. 9 | */ 10 | 11 | // Include pawn-natives macros (`SCRIPT_API`) and lookups (`IPlayer&`). 12 | #include 13 | 14 | // To get the component. 15 | #include "weather-component.hpp" 16 | 17 | // Various methods of lookup up a parameter by ID to return a pointer to the native. 18 | namespace pawn_natives 19 | { 20 | template <> 21 | struct ParamLookup 22 | { 23 | static IWeatherRegion& ValReq(cell ref) 24 | { 25 | if (auto pool = WeatherComponent::getInstance()) 26 | { 27 | auto ptr = pool->getWeatherRegion(ref); 28 | if (ptr) 29 | { 30 | return *ptr; 31 | } 32 | } 33 | throw pawn_natives::ParamCastFailure(); 34 | } 35 | 36 | static IWeatherRegion* Val(cell ref) noexcept 37 | { 38 | if (auto pool = WeatherComponent::getInstance()) 39 | { 40 | return pool->getWeatherRegion(ref); 41 | } 42 | return nullptr; 43 | } 44 | }; 45 | 46 | template <> 47 | class ParamCast 48 | { 49 | public: 50 | ParamCast(AMX* amx, cell* params, int idx) noexcept 51 | { 52 | value_ = ParamLookup::Val(params[idx]); 53 | } 54 | 55 | ~ParamCast() 56 | { 57 | } 58 | 59 | ParamCast(ParamCast const&) = delete; 60 | ParamCast(ParamCast&&) = delete; 61 | 62 | operator IWeatherRegion* () 63 | { 64 | return value_; 65 | } 66 | 67 | static constexpr int Size = 1; 68 | 69 | private: 70 | IWeatherRegion* value_; 71 | }; 72 | 73 | template <> 74 | class ParamCast 75 | { 76 | public: 77 | ParamCast(AMX* amx, cell* params, int idx) 78 | : value_(ParamLookup::ValReq(params[idx])) 79 | { 80 | } 81 | 82 | ~ParamCast() 83 | { 84 | } 85 | 86 | ParamCast(ParamCast const&) = delete; 87 | ParamCast(ParamCast&&) = delete; 88 | 89 | operator IWeatherRegion& () 90 | { 91 | return value_; 92 | } 93 | 94 | static constexpr int Size = 1; 95 | 96 | private: 97 | IWeatherRegion& value_; 98 | }; 99 | 100 | template <> 101 | class ParamCast 102 | { 103 | public: 104 | ParamCast(AMX*, cell*, int) = delete; 105 | ParamCast() = delete; 106 | }; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /interface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This Source Code Form is subject to the terms of the Mozilla Public License, 5 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 6 | * obtain one at http://mozilla.org/MPL/2.0/. 7 | * 8 | * The original code is copyright (c) 2022, open.mp team and contributors. 9 | */ 10 | 11 | // This file should go somewhere like ``, where other components can see it. 12 | 13 | // Required for most of open.mp. 14 | #include 15 | 16 | enum class E_WEATHER 17 | { 18 | UNKNOWN, 19 | SUNNY, 20 | RAINING, 21 | WINDY, 22 | SNOWING, 23 | SLEET, 24 | CLOUDY, 25 | HOT, 26 | FOGGY, 27 | STORMY, 28 | DRIZZLING, 29 | }; 30 | 31 | // This is just a generic container, it doesn't inherit from anything. For most components this 32 | // represents the most important part - the entity that the component manages. Be it objects, 33 | // checkpoints, text draws, or weather regions. 34 | struct IWeatherRegion 35 | { 36 | // Generic name. `StringView` is ABI stable. 37 | virtual StringView getName() const = 0; 38 | 39 | // Generic location. Could also be some map coordinates. `StringView` is ABI stable. 40 | virtual StringView getLocation() const = 0; 41 | 42 | // Get the current weather. 43 | virtual E_WEATHER getWeather() const = 0; 44 | 45 | // Get the ID of this region, used for pool lookups. 46 | virtual int getID() const = 0; 47 | }; 48 | 49 | // If this data is to be used in other components only share an ABI stable base class. 50 | struct IWeatherExtension : IExtension 51 | { 52 | // Visit https://open.mp/uid to generate a new unique ID (different to the component UID). 53 | PROVIDE_EXT_UID(/* UID GOES HERE */); 54 | 55 | // Public methods to get and set this player's weather region. 56 | virtual IWeatherRegion* getWeatherRegion() = 0; 57 | 58 | virtual void setWeatherRegion(IWeatherRegion*) = 0; 59 | }; 60 | 61 | // If other components want to subscribe to our weather event they must implement this interface. 62 | struct WeatherEventHandler 63 | { 64 | // There's only one event - that triggered when the weather in a region changes. 65 | virtual void onWeatherChange(IWeatherRegion& where, E_WEATHER oldWeather, E_WEATHER newWeather) = 0; 66 | }; 67 | 68 | // If this data is to be used in other components only share an ABI stable base class. 69 | struct IWeatherComponent : IComponent 70 | { 71 | // Visit https://open.mp/uid to generate a new unique ID (different to the extension UID). 72 | PROVIDE_UID(/* UID GOES HERE */); 73 | 74 | // Public methods to get and set this player's weather region. 75 | virtual IWeatherRegion* createWeatherRegion(StringView name, StringView location) = 0; 76 | 77 | // Public methods to get and set this player's weather region. 78 | virtual bool destroyWeatherRegion(IWeatherRegion* region) = 0; 79 | 80 | // Look up a region by name. 81 | virtual IWeatherRegion* getWeatherRegion(StringView name) = 0; 82 | 83 | // Look up a region by name. 84 | virtual IWeatherRegion* getWeatherRegion(int id) = 0; 85 | 86 | // A way for other components to look up and subscribe to this component's events. 87 | virtual IEventDispatcher& getEventDispatcher() = 0; 88 | }; 89 | -------------------------------------------------------------------------------- /weather-component.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This Source Code Form is subject to the terms of the Mozilla Public License, 5 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 6 | * obtain one at http://mozilla.org/MPL/2.0/. 7 | * 8 | * The original code is copyright (c) 2022, open.mp team and contributors. 9 | */ 10 | 11 | // Required for most of open.mp. 12 | #include 13 | 14 | // This is the private implementation of the public interface. We must know the interface. 15 | #include "interface.hpp" 16 | 17 | // Import the pawn event. 18 | #include 19 | 20 | // The code to manage a "pool" (array/collection) of "entities" (things). 21 | #include 22 | 23 | // Include the entity's definition. 24 | #include "weather-region.hpp" 25 | 26 | // Import open.mp structures that aren't ABI safe. 27 | using namespace Impl; 28 | 29 | // `final` so we don't need virtual destructors. Also because we know it isn't inherited. 30 | class WeatherComponent final 31 | // This class is an implementation of the publicly shared `IWeatherComponent` interface. 32 | : public IWeatherComponent 33 | // The implementation includes player connection events to know when new players join. 34 | , public PlayerConnectEventHandler 35 | // The implementation includes pawn script events to know when new scripts load. 36 | , public PawnEventHandler 37 | // The implementation includes server tick events to periodically check for weather updates. 38 | , public CoreEventHandler 39 | { 40 | private: 41 | // Hold a reference to the main server core. 42 | ICore* core_ = nullptr; 43 | 44 | // We use the pawn componet to add and remove script load listeners. 45 | IPawnComponent* pawn_; 46 | 47 | // This is a "pool" - it holds a list of "entities". 48 | MarkedPoolStorage pool_; 49 | 50 | // The next time to update region's weather. 51 | TimePoint nextUpdate_ = TimePoint::min(); 52 | 53 | // Create a store for other components to be informed when the weather changes. 54 | DefaultEventDispatcher eventDispatcher_; 55 | 56 | inline static WeatherComponent* instance_ = nullptr; 57 | 58 | public: 59 | // Implementations of the various methods from the public API. 60 | IWeatherRegion* createWeatherRegion(StringView name, StringView location) override; 61 | 62 | bool destroyWeatherRegion(IWeatherRegion* region) override; 63 | 64 | IWeatherRegion* getWeatherRegion(StringView name) override; 65 | 66 | IWeatherRegion* getWeatherRegion(int id) override; 67 | 68 | IEventDispatcher& getEventDispatcher() override; 69 | 70 | // Required component methods. 71 | StringView componentName() const override; 72 | 73 | SemanticVersion componentVersion() const override; 74 | 75 | void onLoad(ICore* c) override; 76 | 77 | void onInit(IComponentList* components) override; 78 | 79 | void onReady() override; 80 | 81 | void onFree(IComponent* component) override; 82 | 83 | void free() override; 84 | 85 | void reset() override; 86 | 87 | // Connect event methods. 88 | void onPlayerConnect(IPlayer& player) override; 89 | 90 | // Pawn event methods. 91 | void onAmxLoad(IPawnScript& script) override; 92 | 93 | void onAmxUnload(IPawnScript& script) override; 94 | 95 | // Update event methods. 96 | void onTick(Microseconds elapsed, TimePoint now) override; 97 | 98 | // More methods to be used only in this component, with more implementation details knowledge. 99 | static WeatherComponent* getInstance(); 100 | 101 | // When this component is destroyed we need to tell any linked components this it is gone. 102 | ~WeatherComponent(); 103 | }; 104 | -------------------------------------------------------------------------------- /natives.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2022, open.mp team and contributors. 7 | */ 8 | 9 | // Required for most of open.mp. 10 | #include 11 | 12 | // Include the globally shared definitions for this component. 13 | #include "interface.hpp" 14 | 15 | // Contains wrappers for pool lookups from IDs. 16 | #include "natives.hpp" 17 | 18 | // `SCRIPT_API` is an enhanced wrapper around the old *pawn-natives* system: 19 | // 20 | // https://github.com/Y-Less/pawn-natives 21 | // 22 | SCRIPT_API(RWW_Create, int(String const& name, String const& location)) 23 | { 24 | // Try get a reference to the controlling component. 25 | if (auto rww = WeatherComponent::getInstance()) 26 | { 27 | // Call a method on the component. 28 | if (auto ret = rww->createWeatherRegion(name, location)) 29 | { 30 | // Pawn wants the ID, not the pointer. 31 | return ret->getID(); 32 | } 33 | } 34 | // Natives return `0`/`false` by default if parameter lookups fail. 35 | return 0; 36 | } 37 | 38 | SCRIPT_API(RWW_Destroy, bool(IWeatherRegion& region)) 39 | { 40 | // Try get a reference to the controlling component. 41 | if (auto rww = WeatherComponent::getInstance()) 42 | { 43 | rww->destroyWeatherRegion(®ion); 44 | // Using the region here is use-after-free. 45 | return true; 46 | } 47 | return false; 48 | } 49 | 50 | // `IWeatherRegion&` calls the parameter lookup from ID and can auto-fail. 51 | SCRIPT_API(RWW_GetName, bool(IWeatherRegion& region, OutputOnlyString& name)) 52 | { 53 | name = region.getName(); 54 | // Natives return `0`/`false` by default if parameter lookups fail. 55 | return true; 56 | } 57 | 58 | // `OutputOnlyString` translates in pawn to a `string/length` pair. 59 | SCRIPT_API(RWW_GetLocation, bool(IWeatherRegion& region, OutputOnlyString& name)) 60 | { 61 | name = region.getLocation(); 62 | // Natives return `0`/`false` by default if parameter lookups fail. 63 | return true; 64 | } 65 | 66 | // Look up the ID, if it doesn't fail the function will be called. 67 | SCRIPT_API(RWW_IsValid, bool(IWeatherRegion&)) 68 | { 69 | // Merely calling this function is enough to validate the region ID exists. 70 | return true; 71 | } 72 | 73 | SCRIPT_API(RWW_GetWeather, int(IWeatherRegion& region)) 74 | { 75 | return static_cast(region.getWeather()); 76 | } 77 | 78 | // `IPlayer&` lookup is in-built. 79 | SCRIPT_API(RWW_SetPlayerRegion, bool(IPlayer& player, IWeatherRegion& region)) 80 | { 81 | // Get the extension data for this player, created when they connected. 82 | if (auto data = queryExtension(player)) 83 | { 84 | // Player, extension data, and region all exist. 85 | data->setWeatherRegion(®ion); 86 | // In a full implementation we should also update their weather here, but that's done in 87 | // `WeatherComponent::onTick` and in the example script just to demonstrate a greater 88 | // variety of features. 89 | return true; 90 | } 91 | // Extension data doesn't exist, failed to set the region. 92 | return false; 93 | } 94 | 95 | // Most SDK functions return pointers/references. Here we convert it to an ID. 96 | SCRIPT_API(RWW_GetPlayerRegion, int(IPlayer& player)) 97 | { 98 | // Get the extension data for this player, created when they connected. 99 | if (auto data = queryExtension(player)) 100 | { 101 | // Get their region if they are in one. 102 | if (auto region = data->getWeatherRegion()) 103 | { 104 | return region->getID(); 105 | } 106 | } 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: DontAlign 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveBitFields: false 9 | AlignConsecutiveDeclarations: false 10 | AlignEscapedNewlines: Right 11 | AlignOperands: DontAlign 12 | AlignTrailingComments: false 13 | AllowAllArgumentsOnNextLine: true 14 | AllowAllConstructorInitializersOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortBlocksOnASingleLine: Empty 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: All 20 | AllowShortLambdasOnASingleLine: None 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLoopsOnASingleLine: false 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: false 26 | AlwaysBreakTemplateDeclarations: MultiLine 27 | BinPackArguments: true 28 | BinPackParameters: true 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: false 32 | AfterControlStatement: Never 33 | AfterEnum: false 34 | AfterFunction: true 35 | AfterNamespace: false 36 | AfterObjCDeclaration: false 37 | AfterStruct: false 38 | AfterUnion: false 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakBeforeBinaryOperators: All 49 | BreakBeforeBraces: Allman 50 | BreakBeforeInheritanceComma: false 51 | BreakInheritanceList: BeforeColon 52 | BreakBeforeTernaryOperators: true 53 | BreakConstructorInitializersBeforeComma: false 54 | BreakConstructorInitializers: BeforeComma 55 | BreakAfterJavaFieldAnnotations: false 56 | BreakStringLiterals: true 57 | ColumnLimit: 0 58 | CommentPragmas: '^ IWYU pragma:' 59 | CompactNamespaces: false 60 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 61 | ConstructorInitializerIndentWidth: 4 62 | ContinuationIndentWidth: 4 63 | Cpp11BracedListStyle: false 64 | DeriveLineEnding: true 65 | DerivePointerAlignment: false 66 | DisableFormat: false 67 | ExperimentalAutoDetectBinPacking: false 68 | FixNamespaceComments: false 69 | ForEachMacros: 70 | - foreach 71 | - Q_FOREACH 72 | - BOOST_FOREACH 73 | IncludeBlocks: Preserve 74 | IncludeCategories: 75 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 76 | Priority: 2 77 | SortPriority: 0 78 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 79 | Priority: 3 80 | SortPriority: 0 81 | - Regex: '.*' 82 | Priority: 1 83 | SortPriority: 0 84 | IncludeIsMainRegex: '(Test)?$' 85 | IncludeIsMainSourceRegex: '' 86 | IndentCaseLabels: false 87 | IndentCaseBlocks: false 88 | IndentGotoLabels: false 89 | IndentPPDirectives: None 90 | IndentExternBlock: AfterExternBlock 91 | IndentWidth: 4 92 | IndentWrappedFunctionNames: false 93 | InsertTrailingCommas: None 94 | JavaScriptQuotes: Leave 95 | JavaScriptWrapImports: true 96 | KeepEmptyLinesAtTheStartOfBlocks: true 97 | MacroBlockBegin: '' 98 | MacroBlockEnd: '' 99 | MaxEmptyLinesToKeep: 1 100 | NamespaceIndentation: Inner 101 | ObjCBinPackProtocolList: Auto 102 | ObjCBlockIndentWidth: 4 103 | ObjCBreakBeforeNestedBlockParam: true 104 | ObjCSpaceAfterProperty: true 105 | ObjCSpaceBeforeProtocolList: true 106 | PenaltyBreakAssignment: 2 107 | PenaltyBreakBeforeFirstCallParameter: 19 108 | PenaltyBreakComment: 300 109 | PenaltyBreakFirstLessLess: 120 110 | PenaltyBreakString: 1000 111 | PenaltyBreakTemplateDeclaration: 10 112 | PenaltyExcessCharacter: 1000000 113 | PenaltyReturnTypeOnItsOwnLine: 60 114 | PointerAlignment: Left 115 | ReflowComments: true 116 | SortIncludes: false 117 | SortUsingDeclarations: true 118 | SpaceAfterCStyleCast: false 119 | SpaceAfterLogicalNot: false 120 | SpaceAfterTemplateKeyword: true 121 | SpaceBeforeAssignmentOperators: true 122 | SpaceBeforeCpp11BracedList: true 123 | SpaceBeforeCtorInitializerColon: true 124 | SpaceBeforeInheritanceColon: true 125 | SpaceBeforeParens: ControlStatements 126 | SpaceBeforeRangeBasedForLoopColon: true 127 | SpaceInEmptyBlock: true 128 | SpaceInEmptyParentheses: false 129 | SpacesBeforeTrailingComments: 1 130 | SpacesInAngles: false 131 | SpacesInConditionalStatement: false 132 | SpacesInContainerLiterals: true 133 | SpacesInCStyleCastParentheses: false 134 | SpacesInParentheses: false 135 | SpacesInSquareBrackets: false 136 | SpaceBeforeSquareBrackets: false 137 | Standard: Latest 138 | StatementMacros: 139 | - Q_UNUSED 140 | - QT_REQUIRE_VERSION 141 | TabWidth: 4 142 | UseCRLF: false 143 | UseTab: true 144 | WhitespaceSensitiveMacros: 145 | - STRINGIZE 146 | - PP_STRINGIZE 147 | - BOOST_PP_STRINGIZE 148 | ... 149 | 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | build/ 18 | 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # DNX 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | 50 | *_i.c 51 | *_p.c 52 | *_i.h 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.tmp_proj 67 | *.log 68 | *.vspscc 69 | *.vssscc 70 | .builds 71 | *.pidb 72 | *.svclog 73 | *.scc 74 | 75 | # Chutzpah Test files 76 | _Chutzpah* 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opendb 83 | *.opensdf 84 | *.sdf 85 | *.cachefile 86 | *.VC.db 87 | *.VC.VC.opendb 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | *.sap 94 | 95 | # TFS 2012 Local Workspace 96 | $tf/ 97 | 98 | # Guidance Automation Toolkit 99 | *.gpState 100 | 101 | # ReSharper is a .NET coding add-in 102 | _ReSharper*/ 103 | *.[Rr]e[Ss]harper 104 | *.DotSettings.user 105 | 106 | # JustCode is a .NET coding add-in 107 | .JustCode 108 | 109 | # TeamCity is a build add-in 110 | _TeamCity* 111 | 112 | # DotCover is a Code Coverage Tool 113 | *.dotCover 114 | 115 | # NCrunch 116 | _NCrunch_* 117 | .*crunch*.local.xml 118 | nCrunchTemp_* 119 | 120 | # MightyMoose 121 | *.mm.* 122 | AutoTest.Net/ 123 | 124 | # Web workbench (sass) 125 | .sass-cache/ 126 | 127 | # Installshield output folder 128 | [Ee]xpress/ 129 | 130 | # DocProject is a documentation generator add-in 131 | DocProject/buildhelp/ 132 | DocProject/Help/*.HxT 133 | DocProject/Help/*.HxC 134 | DocProject/Help/*.hhc 135 | DocProject/Help/*.hhk 136 | DocProject/Help/*.hhp 137 | DocProject/Help/Html2 138 | DocProject/Help/html 139 | 140 | # Click-Once directory 141 | publish/ 142 | 143 | # Publish Web Output 144 | *.[Pp]ublish.xml 145 | *.azurePubxml 146 | # TODO: Comment the next line if you want to checkin your web deploy settings 147 | # but database connection strings (with potential passwords) will be unencrypted 148 | #*.pubxml 149 | *.publishproj 150 | 151 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 152 | # checkin your Azure Web App publish settings, but sensitive information contained 153 | # in these scripts will be unencrypted 154 | PublishScripts/ 155 | 156 | # NuGet Packages 157 | *.nupkg 158 | # The packages folder can be ignored because of Package Restore 159 | **/packages/* 160 | # except build/, which is used as an MSBuild target. 161 | !**/packages/build/ 162 | # Uncomment if necessary however generally it will be regenerated when needed 163 | #!**/packages/repositories.config 164 | # NuGet v3's project.json files produces more ignoreable files 165 | *.nuget.props 166 | *.nuget.targets 167 | 168 | # Microsoft Azure Build Output 169 | csx/ 170 | *.build.csdef 171 | 172 | # Microsoft Azure Emulator 173 | ecf/ 174 | rcf/ 175 | 176 | # Windows Store app package directories and files 177 | AppPackages/ 178 | BundleArtifacts/ 179 | Package.StoreAssociation.xml 180 | _pkginfo.txt 181 | 182 | # Visual Studio cache files 183 | # files ending in .cache can be ignored 184 | *.[Cc]ache 185 | # but keep track of directories ending in .cache 186 | !*.[Cc]ache/ 187 | 188 | # Others 189 | ClientBin/ 190 | ~$* 191 | *~ 192 | *.dbmdl 193 | *.dbproj.schemaview 194 | *.jfm 195 | *.pfx 196 | *.publishsettings 197 | node_modules/ 198 | orleans.codegen.cs 199 | 200 | # Since there are multiple workflows, uncomment next line to ignore bower_components 201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 202 | #bower_components/ 203 | 204 | # RIA/Silverlight projects 205 | Generated_Code/ 206 | 207 | # Backup & report files from converting an old project file 208 | # to a newer Visual Studio version. Backup files are not needed, 209 | # because we have git ;-) 210 | _UpgradeReport_Files/ 211 | Backup*/ 212 | UpgradeLog*.XML 213 | UpgradeLog*.htm 214 | 215 | # SQL Server files 216 | *.mdf 217 | *.ldf 218 | 219 | # Business Intelligence projects 220 | *.rdl.data 221 | *.bim.layout 222 | *.bim_*.settings 223 | 224 | # Microsoft Fakes 225 | FakesAssemblies/ 226 | 227 | # GhostDoc plugin setting file 228 | *.GhostDoc.xml 229 | 230 | # Node.js Tools for Visual Studio 231 | .ntvs_analysis.dat 232 | 233 | # Visual Studio 6 build log 234 | *.plg 235 | 236 | # Visual Studio 6 workspace options file 237 | *.opt 238 | 239 | # Visual Studio LightSwitch build output 240 | **/*.HTMLClient/GeneratedArtifacts 241 | **/*.DesktopClient/GeneratedArtifacts 242 | **/*.DesktopClient/ModelManifest.xml 243 | **/*.Server/GeneratedArtifacts 244 | **/*.Server/ModelManifest.xml 245 | _Pvt_Extensions 246 | 247 | # Paket dependency manager 248 | .paket/paket.exe 249 | paket-files/ 250 | 251 | # FAKE - F# Make 252 | .fake/ 253 | 254 | # JetBrains Rider 255 | .idea/ 256 | *.sln.iml 257 | 258 | # CodeRush 259 | .cr/ 260 | 261 | # Python Tools for Visual Studio (PTVS) 262 | __pycache__/ 263 | *.pyc 264 | 265 | /server/src/Networking/Legacy/CMakeFiles/*.stamp 266 | *.depend 267 | *.stamp 268 | *.list 269 | *.rule 270 | *.filters 271 | *.vcxproj 272 | *.cmake 273 | *.bin 274 | /Win32-Debug 275 | /includes/fmat 276 | /includes/gmock 277 | /includes/gtest 278 | /includes/logger 279 | /includes/pawn 280 | /includes/raknet 281 | /includes/server 282 | /includes/tinydir 283 | /includes/utils 284 | *.sln 285 | *.tlog 286 | /open.mp/Win32-Debug/temp/gtest/gtest.idb 287 | /open.mp/Win32-Debug 288 | /CMakeFiles 289 | *.pc 290 | /CMakeCache.txt 291 | *.amx 292 | *.i 293 | .vscode/ -------------------------------------------------------------------------------- /real-world-weather.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2022, open.mp team and contributors. 7 | */ 8 | 9 | #if defined _INC_real_world_weather 10 | #endinput 11 | #endif 12 | #define _INC_real_world_weather 13 | 14 | /** 15 | * 16 | * 17 | * (c) Copyright 2022, open.mp team. 18 | * 19 | * 20 | * This library uses the enhanced pawndoc.xsl from 21 | * pawn-lang/pawndoc. 22 | * This XSL has features such as library and markdown support, and will not 23 | * render this message when used. 24 | * 25 | * 26 | */ 27 | 28 | ///

29 | 30 | #pragma tabsize 4 31 | 32 | /** 33 | * real-world-weather 34 | */ 35 | const RWW:INVALID_RWW_REGION = RWW:0; 36 | 37 | ///

38 | /** 39 | * real-world-weather 40 | *

Weather types 41 | */ 42 | enum E_WEATHER:E_WEATHER__ 43 | { 44 | E_WEATHER_UNKNOWN, 45 | E_WEATHER_SUNNY, 46 | E_WEATHER_RAINING, 47 | E_WEATHER_WINDY, 48 | E_WEATHER_SNOWING, 49 | E_WEATHER_SLEET, 50 | E_WEATHER_CLOUDY, 51 | E_WEATHER_HOT, 52 | E_WEATHER_FOGGY, 53 | E_WEATHER_STORMY, 54 | E_WEATHER_DRIZZLING 55 | } 56 | static stock E_WEATHER:_@E_WEATHER() { return E_WEATHER__; } 57 | 58 | /** 59 | * real-world-weather 60 | * Create a region for real-world weather. 61 | * The name of the region. 62 | * The real-world location this region mirrors. 63 | * Creates a weather region whose weather matches that of a given real-world location. 64 | * 65 | * 0 - The region was not created.
66 | * n - The ID of the created region. 67 | *
68 | */ 69 | native RWW:RWW_Create(const name[], const location[]); 70 | 71 | /** 72 | * real-world-weather 73 | * Destroy a region for real-world weather. 74 | * The ID of the region to destroy. 75 | * Did this region exist? 76 | */ 77 | native bool:RWW_Destroy(RWW:region); 78 | 79 | /** 80 | * real-world-weather 81 | * Get the real-world weather. 82 | * The ID of the region to check. 83 | * Does this region exist? 84 | */ 85 | native bool:RWW_IsValid(RWW:region); 86 | 87 | /** 88 | * real-world-weather 89 | * Get the real-world weather. 90 | * The ID of the region to get the weather of. 91 | * The weather currently in this region. 92 | */ 93 | native E_WEATHER:RWW_GetWeather(RWW:region); 94 | 95 | /** 96 | * real-world-weather 97 | * Get the name of a real-world weather. 98 | * The ID of the region to get the name of. 99 | * The return value for the name of the region. 100 | * The size of the return array. 101 | * Does this region exist? 102 | */ 103 | native bool:RWW_GetName(RWW:region, name[], size = sizeof (name)); 104 | 105 | /** 106 | * real-world-weather 107 | * Get the location of a real-world weather. 108 | * The ID of the region to get the location of. 109 | * The return value for the real-world location this region mirrors. 110 | * The size of the return array. 111 | * Does this region exist? 112 | */ 113 | native bool:RWW_GetLocation(RWW:region, location[], size = sizeof (location)); 114 | 115 | /** 116 | * real-world-weather 117 | * Get the string description of a weather type. 118 | * The weather to get. 119 | * The return value for the weather description. 120 | * The size of the return array. 121 | * Does this weather type exist? 122 | */ 123 | stock bool:RWW_GetDescription(E_WEATHER:weather, description[], size = sizeof (description)) 124 | { 125 | if (E_WEATHER_UNKNOWN < weather <= E_WEATHER_DRIZZLING) 126 | { 127 | static weatherNames[][] = { 128 | "Sunny", 129 | "Raining", 130 | "Windy", 131 | "Snowing", 132 | "Sleet", 133 | "Cloudy", 134 | "Hot", 135 | "Foggy", 136 | "Stormy", 137 | "Drizzling" 138 | }; 139 | description[0] = '\0'; 140 | strcat(description, weatherNames[_:weather - 1], size); 141 | return true; 142 | } 143 | return false; 144 | } 145 | 146 | /** 147 | * real-world-weather 148 | * Store where the player is in their extension data. 149 | * The player to be marked as in this region. 150 | */ 151 | native RWW:RWW_GetPlayerRegion(playerid); 152 | 153 | /** 154 | * real-world-weather 155 | * Store where the player is in their extension data. 156 | * The player to be marked as in this region. 157 | * The ID of the region to set them in. 158 | * Player is connected and the region exists. 159 | */ 160 | native bool:RWW_SetPlayerRegion(playerid, RWW:region); 161 | 162 | /** 163 | * real-world-weather 164 | * The ID of the region that changed. 165 | * The old weather in this region. 166 | * The new weather in this region. 167 | * This callback is triggered when the weather changes. 168 | * This is called every time the weather in a real-world location changes. It can be 169 | * used to update the in-game weather for players. 170 | */ 171 | forward OnWeatherChange(RWW:region, E_WEATHER:previous, E_WEATHER:current); 172 | 173 | -------------------------------------------------------------------------------- /weather-component.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2022, open.mp team and contributors. 7 | */ 8 | 9 | // Include pawn-natives macros (`SCRIPT_API`) and lookups (`IPlayer&`). 10 | #include 11 | 12 | // Include a few function implementations. Should only be included once. 13 | #include 14 | 15 | // Include the component's definition. 16 | #include "weather-component.hpp" 17 | 18 | // Include the entity's definition. 19 | #include "weather-region.hpp" 20 | 21 | // Include the player data's definition. 22 | #include "weather-extension.hpp" 23 | 24 | // Implementations of the various methods from the public API. 25 | IWeatherRegion* WeatherComponent::createWeatherRegion(StringView name, StringView location) 26 | { 27 | // Pool emplacement automatically assigns and sets an ID. It calls the constructor of the 28 | // concrete implementation, defined in the pool template types, so only this component can 29 | // construct weather regions. All other components see merely the public interface. 30 | return pool_.emplace(name, location); 31 | } 32 | 33 | bool WeatherComponent::destroyWeatherRegion(IWeatherRegion* region) 34 | { 35 | // Since we are in the component, we don't need to exclusively deal with the external API. 36 | int id = static_cast(region)->getID(); 37 | // Loop over all the players in the server. 38 | for (auto player : core_->getPlayers().entries()) 39 | { 40 | // Look up the custom data we added to the player for this component. 41 | if (IWeatherExtension* data = queryExtension(player)) 42 | { 43 | // Check if they are in the region being destroyed. 44 | if (data->getWeatherRegion() == region) 45 | { 46 | // If so, remove them from it. 47 | data->setWeatherRegion(nullptr); 48 | } 49 | } 50 | } 51 | // Destroy the region. 52 | pool_.release(id, false); 53 | // Success! 54 | return true; 55 | } 56 | 57 | IWeatherRegion* WeatherComponent::getWeatherRegion(StringView name) 58 | { 59 | // Loop over all the created regions. 60 | for (auto region : pool_) 61 | { 62 | // Check if the region matches the name. 63 | if (region->getName() == name) 64 | { 65 | // This region has a matching name, return the interface. 66 | return region; 67 | } 68 | } 69 | // No matching regions found. 70 | return nullptr; 71 | } 72 | 73 | IWeatherRegion* WeatherComponent::getWeatherRegion(int id) 74 | { 75 | // Pools have in-built methods for lookups by ID. 76 | return pool_.get(id); 77 | } 78 | 79 | IEventDispatcher& WeatherComponent::getEventDispatcher() 80 | { 81 | return eventDispatcher_; 82 | } 83 | 84 | // Required component methods. 85 | StringView WeatherComponent::componentName() const 86 | { 87 | return "Full Template"; 88 | } 89 | 90 | SemanticVersion WeatherComponent::componentVersion() const 91 | { 92 | return SemanticVersion(0, 0, 1, 0); 93 | } 94 | 95 | void WeatherComponent::onLoad(ICore* c) 96 | { 97 | // Cache core, listen to player events. 98 | core_ = c; 99 | // Register this component as wanting to be informed when a player (dis)connects. 100 | core_->getPlayers().getPlayerConnectDispatcher().addEventHandler(this); 101 | // Register this component as wanting to be informed when a tick happens. 102 | core_->getEventDispatcher().addEventHandler(this); 103 | // Record the reference to `ICore` used by *pawn-natives*. 104 | setAmxLookups(core_); 105 | // Done. 106 | core_->printLn("Full component template loaded."); 107 | } 108 | 109 | void WeatherComponent::onInit(IComponentList* components) 110 | { 111 | // Cache components, add event handlers here. 112 | pawn_ = components->queryComponent(); 113 | 114 | if (pawn_) 115 | { 116 | // For the legacy `amx_` C API this call sets the correct pointers so that pawn 117 | // function calls call the original versions within the server. 118 | setAmxFunctions(pawn_->getAmxFunctions()); 119 | // For the pawn-natives system this call sets the various component references used for 120 | // parameter value lookups. 121 | setAmxLookups(components); 122 | // Register this component as wanting to be informed when a script is loaded. 123 | pawn_->getEventDispatcher().addEventHandler(this); 124 | } 125 | } 126 | 127 | void WeatherComponent::onReady() 128 | { 129 | // Fire events here at earliest. 130 | } 131 | 132 | void WeatherComponent::onFree(IComponent* component) 133 | { 134 | // Invalidate pawn pointer so it can't be used past this point. 135 | if (component == pawn_) 136 | { 137 | // Remove the internal pointer. 138 | pawn_ = nullptr; 139 | // Remove the pointers to the various `amx_` function implementations. 140 | setAmxFunctions(); 141 | // Remove all pool lookup pointers. 142 | setAmxLookups(); 143 | } 144 | } 145 | 146 | void WeatherComponent::free() 147 | { 148 | // Deletes the component. 149 | delete this; 150 | } 151 | 152 | void WeatherComponent::reset() 153 | { 154 | // Resets data when the mode changes. 155 | } 156 | 157 | // Connect event methods. 158 | void WeatherComponent::onPlayerConnect(IPlayer& player) 159 | { 160 | // Allocate a new copy of the extension and register it for `queryExtension` lookups. 161 | player.addExtension(new WeatherExtension(), true); 162 | } 163 | 164 | // Pawn event methods. 165 | void WeatherComponent::onAmxLoad(IPawnScript& script) 166 | { 167 | // Because we're using `SCRIPT_API` this call automatically registers the declared natives. 168 | pawn_natives::AmxLoad(script.GetAMX()); 169 | } 170 | 171 | void WeatherComponent::onAmxUnload(IPawnScript& script) 172 | { 173 | } 174 | 175 | // Update event methods. 176 | void WeatherComponent::onTick(Microseconds elapsed, TimePoint now) 177 | { 178 | // Check if we need to recheck. 179 | if (pawn_ && now > nextUpdate_) 180 | { 181 | // Loop through all the regions and update their weather. 182 | for (IWeatherRegion* region : pool_) 183 | { 184 | // Call a method on the interface to get the current weather. 185 | E_WEATHER prev = region->getWeather(); 186 | // Call a method on the private implementation to update the weather. 187 | bool changed = static_cast(region)->updateWeather(); 188 | // Check if the weather has changed. 189 | if (changed) 190 | { 191 | // The weather has changed. 192 | E_WEATHER cur = region->getWeather(); 193 | // Emit an event for other components. 194 | eventDispatcher_.dispatch(&WeatherEventHandler::onWeatherChange, *region, prev, cur); 195 | // Tell pawn. 196 | int id = region->getID(); 197 | for (IPawnScript* script : pawn_->sideScripts()) 198 | { 199 | // `forward OnWeatherChange(region, E_WEATHER:prev, E_WEATHER:cur);` 200 | script->Call("OnWeatherChange", DefaultReturnValue_False, id, prev, cur); 201 | } 202 | // Call in the gamemode after all filterscripts. 203 | if (auto script = pawn_->mainScript()) 204 | { 205 | script->Call("OnWeatherChange", DefaultReturnValue_False, id, prev, cur); 206 | } 207 | // Update all players in this region. 208 | for (IPlayer* player : core_->getPlayers().entries()) 209 | { 210 | // Get the extension data for this player, which stores their region. 211 | if (IWeatherExtension* data = queryExtension(player)) 212 | { 213 | // Are they in the current one? 214 | if (data->getWeatherRegion() == region) 215 | { 216 | // Convert the component weather ID to an in-game ID. 217 | switch (cur) 218 | { 219 | case E_WEATHER::SUNNY: 220 | case E_WEATHER::HOT: 221 | // And set their weather. 222 | player->setWeather(11); 223 | break; 224 | case E_WEATHER::RAINING: 225 | case E_WEATHER::STORMY: 226 | case E_WEATHER::DRIZZLING: 227 | player->setWeather(8); 228 | break; 229 | case E_WEATHER::WINDY: 230 | case E_WEATHER::CLOUDY: 231 | case E_WEATHER::FOGGY: 232 | player->setWeather(12); 233 | break; 234 | case E_WEATHER::SNOWING: 235 | case E_WEATHER::SLEET: 236 | player->setWeather(19); 237 | break; 238 | default: 239 | break; 240 | } 241 | } 242 | } 243 | } 244 | } 245 | } 246 | // Update five times a second. 247 | nextUpdate_ += std::chrono::milliseconds(200); 248 | } 249 | } 250 | 251 | // More methods to be used only in this component, with more implementation details knowledge. 252 | WeatherComponent* WeatherComponent::getInstance() 253 | { 254 | // Poor man's `Singleton`. 255 | if (instance_ == nullptr) 256 | { 257 | instance_ = new WeatherComponent(); 258 | } 259 | return instance_; 260 | } 261 | 262 | // When this component is destroyed we need to tell any linked components this it is gone. 263 | WeatherComponent::~WeatherComponent() 264 | { 265 | // Clean up what you did above. 266 | if (pawn_) 267 | { 268 | pawn_->getEventDispatcher().removeEventHandler(this); 269 | } 270 | if (core_) 271 | { 272 | core_->getPlayers().getPlayerConnectDispatcher().removeEventHandler(this); 273 | core_->getEventDispatcher().removeEventHandler(this); 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | --------------------------------------------------------------------------------