diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..649dab03 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +Saves +*.pdf +Data/Files +.git +Backups +Data/Logs \ No newline at end of file diff --git a/Data/Scripts/System/Misc/ServerList.cs b/Data/Scripts/System/Misc/ServerList.cs index 78b5d019..d9b76085 100644 --- a/Data/Scripts/System/Misc/ServerList.cs +++ b/Data/Scripts/System/Misc/ServerList.cs @@ -10,18 +10,18 @@ namespace Server.Misc { public class ServerList { - /* + /* * The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses * are private network addresses and AutoDetect is 'true' then RunUO will attempt to discover your public IP address * for you automatically. * * If you do not plan on allowing clients outside of your LAN to connect, you can set AutoDetect to 'false' and leave * Address set to 'null'. - * + * * If your public IP address cannot be determined, you must change the value of Address to your public IP address * manually to allow clients outside of your LAN to connect to your server. Address can be either an IP address or * a hostname that will be resolved when RunUO starts. - * + * * If you want players outside your LAN to be able to connect to your server and you are behind a router, you must also * forward TCP port 2593 to your private IP address. The procedure for doing this varies by manufacturer but generally * involves configuration of the router through your web browser. @@ -33,12 +33,14 @@ public class ServerList * properly and fully supports listening on multiple ports. If a client with a public IP address is connecting to a * locally private address, the server will direct the client to either the AutoDetected IP address or the manually entered * IP address or hostname, whichever is applicable. Loopback clients will be directed to loopback. - * + * * If you would like to listen on additional ports (i.e. 22, 23, 80, for clients behind highly restrictive egress * firewalls) or specific IP adddresses you can do so by modifying the file SocketOptions.cs found in this directory. */ public static readonly string Address = MySettings.S_Address; + public static readonly bool EnforceAddress = MySettings.S_EnforceAddress; + public static readonly string ServerName = MySettings.S_ServerName; public static readonly bool AutoDetect = MySettings.S_AutoDetect; @@ -71,10 +73,17 @@ private static void EventSink_ServerList( ServerListEventArgs e ) if ( IsPrivateNetwork( localAddress ) ) { ipep = (IPEndPoint)s.RemoteEndPoint; - if ( !IsPrivateNetwork( ipep.Address ) && m_PublicAddress != null ) + if (!IsPrivateNetwork( ipep.Address ) && m_PublicAddress != null ) localAddress = m_PublicAddress; } + if ( EnforceAddress ) { + Console.WriteLine("ServerList: EnforceAddress is set to true, overriding the detected IP"); + localAddress = m_PublicAddress; + } + + Console.WriteLine("ServerList: Serving the Game Server at {0}", localAddress.ToString()); + e.AddServer( ServerName, new IPEndPoint( localAddress, localPort ) ); } catch diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..392ad686 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM mono@sha256:34d816779b1248b5cfd095770b64ecbaf1798e2aca693a91c11a018dce9c7ad5 AS base +WORKDIR /app +COPY . . + +FROM base as builder +WORKDIR /app/Data/System + +RUN mcs -optimize+ \ + -unsafe -t:exe -out:WorldLinux.exe \ + -win32icon:Source/icon.ico -nowarn:219,414 \ + -d:NEWTIMERS -d:NEWPARENT -d:MONO '-recurse:Source/*.cs' + +FROM base as runtime +RUN apt update && apt install -y zlib1g zlib1g-dev +COPY --from=builder /app/Data/System/WorldLinux.exe . +ENTRYPOINT [ "mono", "/app/WorldLinux.exe" ] \ No newline at end of file diff --git a/Info/Scripts/Settings.cs b/Info/Scripts/Settings.cs index c2b42277..484ff857 100644 --- a/Info/Scripts/Settings.cs +++ b/Info/Scripts/Settings.cs @@ -31,7 +31,7 @@ public static class MySettings public static bool ConsoleLog = false; - // These settings will create a button on the Message of the Day. If you do not fill in a website name, the text next to the + // These settings will create a button on the Message of the Day. If you do not fill in a website name, the text next to the // button will simply say Website. When players select the button, it should open their browser to that site. // EXAMPLE: https://google.com @@ -73,7 +73,12 @@ public static class MySettings public static string S_Address = null; - // Here you can enter the name of your server/world + // Skip server address detection and enforce the S_Address value for the game server + // That's useful when your server is behind the NAT or runs in a container + // As an example of a container setup, set S_Address to "127.0.0.1" and S_EnforceAddress to true + public static bool S_EnforceAddress = false; + + // Here you can enter the name of your server/world public static string S_ServerName = "Secrets of Sosaria"; @@ -102,7 +107,7 @@ public static class MySettings // If true, then dungeon environments will have random sounds as you traverse the corridors. - public static bool S_EnableDungeonSoundEffects = true; + public static bool S_EnableDungeonSoundEffects = true; // If true, then the strange portals that lead to deep and dangerous dungeons will have an exit portal. @@ -469,11 +474,11 @@ public static class MySettings public static int S_SpawnMax = 60; - // This settings controls the limit in seconds by which you can be paralyzed by a monster. + // This settings controls the limit in seconds by which you can be paralyzed by a monster. // The default is 10 seconds. It mainly affects mummies, ants, plants and spiders. Setting it to a - // value higher than 10 could mean that the paralyze cooldown is lower than its duration, - // which can lead to frustrating fights as enemies can flee and chain-paralyze a character until they heal - // enough to get back into the fight. + // value higher than 10 could mean that the paralyze cooldown is lower than its duration, + // which can lead to frustrating fights as enemies can flee and chain-paralyze a character until they heal + // enough to get back into the fight. public static double S_paralyzeDuration = 10.0; /////////////////////////////////////////////////////////////////////////////////////////////// @@ -557,7 +562,7 @@ public static class MySettings // If true, then some vendors will have a black market option in their context menus. When used, a different // purchasing screen will be presented to the player. They can see the special crafted items they have in // stock. They will only have one of such item at a time and they will restock the black market during the - // regular stocking schedule. The resources items are made of will be land specific. EXAMPLE: If you can only + // regular stocking schedule. The resources items are made of will be land specific. EXAMPLE: If you can only // get obsidian metal in the Serpent Island, then you will may only find obsidian items in that land. public static bool S_BlackMarket = false; @@ -709,8 +714,8 @@ public static class MySettings /////////////////////////////////////////////////////////////////////////////////////////////// // If true, guards will instantly kill criminal and murderer characters. Otherwise, they will chase - // them in town where any player characters that get hit by the guards will be sent to prison and - // lose some equipment which is limited to stackable items like: potions, bandages, arrows, bolts, + // them in town where any player characters that get hit by the guards will be sent to prison and + // lose some equipment which is limited to stackable items like: potions, bandages, arrows, bolts, // gems, coins, jewels, crystals, reagents, bottles, food, and water. public static bool S_GuardsSentenceDeath = true; diff --git a/README.md b/README.md index 89d96a73..e5b37848 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,53 @@ The source for our world package is freely available on github and we are open t [Conclusion] We seek to honor the legacy of the original developers and caretakers of this game while also making it a more engaging, cohesive, and most importantly fun experience for all. While we are just one fork among many of this project, we wish to provide the best possible user experience through utilizing the methods outlined in our goals. + + +## Running in Docker +When the server is running in a container, we need to enforce the IP of a Game Server to be `127.0.0.1` ( for local development ), or a public IP while running on a VPS. +### Running locally +Edit the `Info/Scripts/Settings.cs` file and set: +```c# +public static string S_Address = "127.0.0.1"; +public static bool S_EnforceAddress = true; +``` +### Development mode +```shell +#tl;dr: docker compose down && docker compose up +``` +All the code changes are getting persisten during the build time. Thus, if you change a code, you want the container image to be rebuilt in order to be reflect you changes. The easiest way to do it, is to destroy the Compose stack: +```sh +docker compose down +``` +and recreate it +```sh +docker compose up +``` +In the most cases, that should rebuild the image in case of changed files. If you want to rebuild the image for sure, you can use a command: +```sh +docker compose up --build +``` +#### Running in a detached mode +To run the server in a detached mode (a one-shot rune), use the `docker compose` to run the server: +``` +docker compose up -d +``` + +In that case, you won't be able to directly interact with the running server (though, it's still possible via the `docker exec..` command). +#### Running in an attached mode +To run the server in an attached mode, use the `docker compose` to run the server without the `-d` flag: +``` +docker compose up +``` + +In that case, you can directly interact with the server, including the Console command. Please be aware, that Ctrl+C will shut down the server. +### Running on a VPS/VDS +Edit the `Info/Scripts/Settings.cs` file and set: +``` +public static string S_Address = ""; +public static bool S_EnforceAddress = true; +``` +Then, use the `docker compose` to run the server: +``` +docker compose up -d +``` \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..28a1a8b3 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,11 @@ +services: + uo: + image: uo + build: . + ports: + - 2593:2593 + volumes: + - ./Saves:/app/Saves + - ./Data/Files:/app/Data/Files + - ./Backups:/app/Backups + - ./Data/Logs:/app/Data/Logs