From e39cec9247aa6f6fd9327d5be8cb17dcebccba8a Mon Sep 17 00:00:00 2001 From: James Dudley Date: Sat, 28 Aug 2021 21:04:40 -0500 Subject: [PATCH] initial commit --- .editorconfig | 15 + .gitattributes | 2 + .github/dependabot.yml | 16 + .github/workflows/build-linux-image.yml | 64 ++++ .github/workflows/update-dockerhub.yml | 21 + .gitignore | 38 ++ .vscode/extensions.json | 6 + .vscode/settings.json | 14 + .vscode/tasks.json | 45 +++ CODE_OF_CONDUCT.md | 14 + CONTRIBUTING.md | 11 + dist.linux/System/UnrealTournament.ini | 486 ++++++++++++++++++++++++ dist.linux/ll-tests/gamesvr-ut99.sh | 174 +++++++++ linux.Dockerfile | 62 +++ 14 files changed, 968 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build-linux-image.yml create mode 100644 .github/workflows/update-dockerhub.yml create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 dist.linux/System/UnrealTournament.ini create mode 100644 dist.linux/ll-tests/gamesvr-ut99.sh create mode 100644 linux.Dockerfile diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3105283 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_size = 4 +indent_style = space +trim_trailing_whitespace = true + +[.travis.yml] +indent_size = 2 + +[windows/**] +end_of_line = crlf \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..723f26f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set default behavior to automatically normalize to linux line endings. +* text=auto eol=lf diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fa6c2b2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + # Enable version updates for Docker + - package-ecosystem: "docker" + # Look for a `Dockerfile` in the `root` directory + directory: "/" + # Check for updates once a week + schedule: + interval: "weekly" + + # Enable version updates for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + time: "11:00" diff --git a/.github/workflows/build-linux-image.yml b/.github/workflows/build-linux-image.yml new file mode 100644 index 0000000..7376312 --- /dev/null +++ b/.github/workflows/build-linux-image.yml @@ -0,0 +1,64 @@ +name: linux/amd64 + +on: + schedule: + - cron: '0 8 * * THU' + push: + branches: [ master ] + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2.3.4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Pull Latest Linux Base Image + run: docker pull debian:bullseye-slim + - name: Build Linux Image + uses: docker/build-push-action@v2.7.0 + with: + context: . + file: ./linux.Dockerfile + tags: | + lacledeslan/gamesvr-ut99:latest + ghcr.io/lacledeslan/gamesvr-ut99:latest + build-args: | + BUILDNODE=GitHub (Run Number: ${{ github.run_number }} Run ID: ${{ github.run_id }}) + SOURCE_COMMIT=${{ github.sha }} + no-cache: true + - name: Test Linux Image + run: docker run --rm lacledeslan/gamesvr-ut99:latest /app/ll-tests/gamesvr-ut99.sh + - name: Login to DockerHub + if: ${{ github.event_name != 'pull_request' }} + uses: docker/login-action@v1.10.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to GitHub Container Registry + if: ${{ github.event_name != 'pull_request' }} + uses: docker/login-action@v1.10.0 + with: + registry: ghcr.io + username: ${{ secrets.GHCR_USERNAME }} + password: ${{ secrets.GHCR_TOKEN }} + - name: Push to Docker HUB + if: ${{ github.event_name != 'pull_request' }} + run: docker push lacledeslan/gamesvr-ut99:latest + - name: Push to GitHub Packages + if: ${{ github.event_name != 'pull_request' }} + run: docker push ghcr.io/lacledeslan/gamesvr-ut99:latest + # - name: Trigger downstream build of lacledeslan/gamesvr-ut99-freeplay + # if: ${{ github.event_name != 'pull_request' }} + # run: |- + # curl -XPOST -u "${{ secrets.GH_PAT_USERNAME }}:${{ secrets.GH_PAT_TOKEN }}" \ + # -H "Accept: application/vnd.github.v3+json" -H "Content-Type: application/json" \ + # --data '{"event_type": "${{ github.repository }} was updated", "client_payload": {"Run Number":"${{ github.run_number }}", "Run ID":"${{ github.run_id }}", "Source Commit":"${{ github.sha }}"}}' \ + # https://api.github.com/repos/LacledesLAN/gamesvr-ut99-freeplay/dispatches diff --git a/.github/workflows/update-dockerhub.yml b/.github/workflows/update-dockerhub.yml new file mode 100644 index 0000000..6f6d2f9 --- /dev/null +++ b/.github/workflows/update-dockerhub.yml @@ -0,0 +1,21 @@ +name: Update Docker Hub Description + +on: + push: + branches: [ master ] + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2.3.4 + - name: Update Docker HUB Description + uses: peter-evans/dockerhub-description@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: lacledeslan/gamesvr-ut99 + short-description: "Unreal Tournament (1999) Dedicated Server in Docker" + readme-filepath: ./readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d94679 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + + +### Linux Cruft ### +*~ +.fuse_hidden* +.directory +.Trash-* +.nfs* + + +### macOS Cruft ### +.AppleDouble +._* +.com.apple.timemachine.donotpresent +.DocumentRevisions-V100 +.DS_Store +.fseventsd +.LSOverride +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + + +### Windows Cruft ### +*.stackdump +*.lnk +[Dd]esktop.ini +ehthumbs.db +ehthumbs_vista.db +Thumbs.db diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..9c461b0 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "editorconfig.editorconfig", + "ms-azuretools.vscode-docker", + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6fe8e77 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "cSpell.words": [ + "buildnode", + "description", + "dockerhub", + "freeplay", + "gamesvr", + "ghcr", + "laclede", + "laclede's", + "lacledeslan", + "qemu" + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..74efb31 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,45 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Linux - Build Image", + "type": "shell", + "command": "docker pull lacledeslan/steamcmd:linux; docker pull debian:bullseye-slim; docker build . -f linux.Dockerfile -t ll/gamesvr-ut99 --no-cache --build-arg BUILDNODE=$env:computername;", + "group": "build", + "problemMatcher": [], + "promptOnClose": true + }, + { + "label": "Linux - Build & Shell In", + "type": "shell", + "command": "docker run -it --net=host --rm ll/gamesvr-ut99;", + "dependsOn": "Linux - Build Image", + "group": "build", + "problemMatcher": [], + "promptOnClose": true + }, + { + "label": "Linux - Build & Execute Self Tests", + "type": "shell", + "command": "docker run -it --rm ll/gamesvr-ut99 /app/ll-tests/gamesvr-ut99.sh;", + "dependsOn": "Linux - Build Image", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "promptOnClose": true + }, + { + "label": "Linux - Build & Run Interactive Server", + "type": "shell", + "command": "docker run -it --rm --net=host ll/gamesvr-ut99 ./ucc-bin server DM-Gael?game=XGame.xDeathMatch -nohomedir -lanplay", + "dependsOn": "Linux - Build Image", + "group": "build", + "problemMatcher": [], + "promptOnClose": true + } + ] +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f94cca1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,14 @@ +# Laclede’s LAN Code of Conduct for Open Source Projects + +The Laclede’s LAN team and community is made up of a mixture of professionals and volunteers from the Greater Saint Louis area and beyond. In the interests of fostering a collaborative environment we have a few ground rules for community participants. + +* Be welcoming, friendly, and patient. +* Be respectful. Disagreement is inevitable, but is no excuse for poor behavior or poor manners. Don't allow frustration with the work to become frustration directed at people. It's important to remember that a community where people feel uncomfortable or threatened is not a productive one. +* Be careful with your words. Remember that sexist, racist, and other exclusionary jokes can potentially be offensive to those around you, even if you did not mean them to be. Do not insult or put down other participants. Behave professionally. +* Be considerate. It is the responsibility of project maintainers to focus on Laclede’s LAN goals. Decisions may be made that reject your code or feature requests that go against our mission. At any time you may fork the projects in accordance with the applicable project license(s). + +When we disagree, we try to understand why. Disagreements, both social and technical, happen all the time and Laclede’s LAN is no exception. It is important that we resolve disagreements and differing views constructively. + +Laclede’s LAN officers and project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. + +Credits for the sources and inspiration of this code of conduct go to [Speak Up!](https://web.archive.org/web/20141109123859/http://speakup.io/coc.html) and [Contributor Covenant](https://archive.fo/ocyAN). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9ff9a1e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing + +First off, thank you for considering contributing to `gamesvr-ut99`. It's people like you that make Laclede's LAN such a great community. + +## Did you find a bug or have questions? + +Let us know by using [GitHub issues](https://github.com/LacledesLAN/gamesvr-ut99/issues) on this repository. + +## Have a fix or feature? + +[Fork this repository](https://help.github.com/articles/fork-a-repo), create a branch with a descriptive name, and submit a pull request. A project maintainer will remove and either merge or provide feedback. diff --git a/dist.linux/System/UnrealTournament.ini b/dist.linux/System/UnrealTournament.ini new file mode 100644 index 0000000..9606436 --- /dev/null +++ b/dist.linux/System/UnrealTournament.ini @@ -0,0 +1,486 @@ +[URL] +Protocol=unreal +ProtocolDescription=Unreal Protocol +Name=Player +Map=Index.unr +LocalMap=CityIntro.unr +Host= +Portal= +MapExt=unr +SaveExt=usa +Port=7777 +Class=Botpack.TMale1 + +[FirstRun] +FirstRun=0 + +[PackageRemap] +UnrealShare=UnrealI + +[Engine.Engine] +GameRenderDevice=SoftDrv.SoftwareRenderDevice +AudioDevice=Galaxy.GalaxyAudioSubsystem +NetworkDevice=IpDrv.TcpNetDriver +DemoRecordingDevice=Engine.DemoRecDriver +Console=UTMenu.UTConsole +Language=int +GameEngine=Engine.GameEngine +EditorEngine=Editor.EditorEngine +WindowedRenderDevice=SoftDrv.SoftwareRenderDevice +RenderDevice=GlideDrv.GlideRenderDevice +DefaultGame=Botpack.DeathMatchPlus +DefaultServerGame=Botpack.DeathMatchPlus +ViewportManager=WinDrv.WindowsClient +Render=Render.Render +Input=Engine.Input +Canvas=Engine.Canvas +CdPath=H: + +[Core.System] +PurgeCacheDays=30 +SavePath=../Save +CachePath=../Cache +CacheExt=.uxx +Paths=../System/*.u +Paths=../Maps/*.unr +Paths=../Textures/*.utx +Paths=../Sounds/*.uax +Paths=../Music/*.umx +Suppress=DevLoad +Suppress=DevSave +Suppress=DevNetTraffic +Suppress=DevGarbage +Suppress=DevKill +Suppress=DevReplace +Suppress=DevSound +Suppress=DevCompile +Suppress=DevBind +Suppress=DevBsp + +[Engine.GameEngine] +CacheSizeMegs=4 +UseSound=True +ServerActors=IpDrv.UdpBeacon +ServerActors=IpServer.UdpServerQuery +ServerActors=IpServer.UdpServerUplink MasterServerAddress=unreal.epicgames.com MasterServerPort=27900 +ServerActors=IpServer.UdpServerUplink MasterServerAddress=master0.gamespy.com MasterServerPort=27900 +ServerActors=IpServer.UdpServerUplink MasterServerAddress=master.mplayer.com MasterServerPort=27900 +ServerActors=UWeb.WebServer +ServerPackages=SoldierSkins +ServerPackages=CommandoSkins +ServerPackages=FCommandoSkins +ServerPackages=SGirlSkins +ServerPackages=BossSkins +ServerPackages=Botpack +ServerPackages=MultiMesh +ServerPackages=Relics +ServerPackages=EpicCustomModels +ServerPackages=TCowMeshSkins +ServerPackages=TNaliMeshSkins +ServerPackages=TSkMSkins +ServerPackages=De + +[WinDrv.WindowsClient] +WindowedViewportX=640 +WindowedViewportY=480 +WindowedColorBits=16 +FullscreenViewportX=640 +FullscreenViewportY=480 +FullscreenColorBits=16 +Brightness=0.500000 +MipFactor=1.000000 +UseDirectDraw=True +UseJoystick=False +CaptureMouse=True +StartupFullscreen=True +CurvedSurfaces=False +LowDetailTextures=False +ScreenFlashes=True +NoLighting=False +SlowVideoBuffering=True +DeadZoneXYZ=True +DeadZoneRUV=False +InvertVertical=False +ScaleXYZ=1000.0 +ScaleRUV=2000.0 +MinDesiredFrameRate=30.0 +Decals=True +NoDynamicLights=False + +[XDrv.XClient] +WindowedViewportX=640 +WindowedViewportY=480 +WindowedColorBits=16 +FullscreenViewportX=640 +FullscreenViewportY=480 +FullscreenColorBits=16 +Brightness=0.500000 +MipFactor=1.000000 +SlowVideoBuffering=False +StartupFullscreen=True +CurvedSurfaces=False +CaptureMouse=True +LowDetailTextures=False +ScreenFlashes=True +NoLighting=False +DeadZoneXYZ=True +DeadZoneRUV=False +InvertVertical=False +ScaleXYZ=1000.0 +ScaleRUV=2000.0 +MinDesiredFrameRate=30.0 + +[Engine.Player] +ConfiguredInternetSpeed=2600 +ConfiguredLanSpeed=20000 + +[Audio.GenericAudioSubsystem] +UseFilter=True +UseSurround=False +UseStereo=True +UseCDMusic=False +UseDigitalMusic=False +UseSpatial=False +UseReverb=False +Use3dHardware=False +LowSoundQuality=False +ReverseStereo=False +Latency=40 +OutputRate=22050Hz +Channels=16 +MusicVolume=160 +SoundVolume=200 +AmbientFactor=0.7 + +[Galaxy.GalaxyAudioSubsystem] +UseDirectSound=True +UseFilter=True +UseSurround=False +UseStereo=True +UseCDMusic=False +UseDigitalMusic=True +UseSpatial=False +UseReverb=True +Use3dHardware=False +LowSoundQuality=False +ReverseStereo=False +Latency=40 +OutputRate=22050Hz +EffectsChannels=16 +DopplerSpeed=9000.000000 +MusicVolume=160 +SoundVolume=200 +AmbientFactor=0.700000 + +[IpDrv.TcpNetDriver] +AllowDownloads=True +ConnectionTimeout=15.0 +InitialConnectTimeout=150.0 +AckTimeout=1.0 +KeepAliveTime=0.2 +MaxClientRate=20000 +SimLatency=0 +RelevantTimeout=5.0 +SpawnPrioritySeconds=1.0 +ServerTravelPause=4.0 +NetServerMaxTickRate=20 +LanServerMaxTickRate=35 +DownloadManagers=IpDrv.HTTPDownload +DownloadManagers=Engine.ChannelDownload + +[IpDrv.HTTPDownload] +RedirectToURL= +ProxyServerHost= +ProxyServerPort=3128 +UseCompression=True + +[Engine.DemoRecDriver] +DemoSpectatorClass=Botpack.CHSpectator +MaxClientRate=25000 +ConnectionTimeout=15.0 +InitialConnectTimeout=500.0 +AckTimeout=1.0 +KeepAliveTime=1.0 +SimLatency=0 +RelevantTimeout=5.0 +SpawnPrioritySeconds=1.0 +ServerTravelPause=4.0 +NetServerMaxTickRate=60 +LanServerMaxTickRate=60 + +[Engine.GameReplicationInfo] +ServerName=Another UT Server +ShortName=UT Server + +[IpDrv.TcpipConnection] +SimPacketLoss=0 +SimLatency=0 + +[IpServer.UdpServerQuery] +GameName=ut + +[IpDrv.UdpBeacon] +DoBeacon=True +BeaconTime=0.50 +BeaconTimeout=5.0 +BeaconProduct=ut + +[SoftDrv.SoftwareRenderDevice] +Translucency=True +VolumetricLighting=True +ShinySurfaces=False +Coronas=False +HighDetailActors=False +HighResTextureSmooth=True +LowResTextureSmooth=False +FastTranslucency=True + +[GlideDrv.GlideRenderDevice] +Translucency=True +VolumetricLighting=True +ShinySurfaces=True +Coronas=True +HighDetailActors=True +DetailBias=-1.500000 +RefreshRate=60Hz +DetailTextures=True +FastUglyRefresh=False +ScreenSmoothing=True +Resolution=Default + +[MetalDrv.MetalRenderDevice] +Translucency=True +VolumetricLighting=True +ShinySurfaces=True +Coronas=True +HighDetailActors=True +DetailTextures=False + +[OpenGLDrv.OpenGLRenderDevice] +Translucency=True +VolumetricLighting=False +ShinySurfaces=True +Coronas=True +HighDetailActors=True +DetailTextures=True + +[D3DDrv.D3DRenderDevice] +Translucency=True +VolumetricLighting=False +ShinySurfaces=True +Coronas=True +HighDetailActors=True +UseMipmapping=True +UseTrilinear=False +UseMultitexture=True +UsePageFlipping=True +UsePalettes=True +UseFullscreen=True +UseGammaCorrection=True +DetailTextures=False +Use3dfx=False +UseTripleBuffering=True +UsePrecache=True +Use32BitTextures=False + +[SglDrv.SglRenderDevice] +Translucency=True +VolumetricLighting=False +ShinySurfaces=False +Coronas=True +HighDetailActors=False +ColorDepth=16 +DetailTextures=False +FastUglyRefresh=False +TextureDetailBias=Near +VertexLighting=False + +[Editor.EditorEngine] +UseSound=True +CacheSizeMegs=6 +GridEnabled=True +SnapVertices=True +SnapDistance=10.000000 +GridSize=(X=16.000000,Y=16.000000,Z=16.000000) +RotGridEnabled=True +RotGridSize=(Pitch=1024,Yaw=1024,Roll=1024) +GameCommandLine=-log +FovAngleDegrees=90.000000 +GodMode=True +AutoSave=False +AutoSaveTimeMinutes=5 +AutoSaveIndex=6 +C_WorldBox=(R=0,G=0,B=107,A=0) +C_GroundPlane=(R=0,G=0,B=63,A=0) +C_GroundHighlight=(R=0,G=0,B=127,A=0) +C_BrushWire=(R=255,G=63,B=63,A=0) +C_Pivot=(R=0,G=255,B=0,A=0) +C_Select=(R=0,G=0,B=127,A=0) +C_AddWire=(R=127,G=127,B=255,A=0) +C_SubtractWire=(R=255,G=192,B=63,A=0) +C_GreyWire=(R=163,G=163,B=163,A=0) +C_Invalid=(R=163,G=163,B=163,A=0) +C_ActorWire=(R=127,G=63,B=0,A=0) +C_ActorHiWire=(R=255,G=127,B=0,A=0) +C_White=(R=255,G=255,B=255,A=0) +C_SemiSolidWire=(R=127,G=255,B=0,A=0) +C_NonSolidWire=(R=63,G=192,B=32,A=0) +C_WireGridAxis=(R=119,G=119,B=119,A=0) +C_ActorArrow=(R=163,G=0,B=0,A=0) +C_ScaleBox=(R=151,G=67,B=11,A=0) +C_ScaleBoxHi=(R=223,G=149,B=157,A=0) +C_Mover=(R=255,G=0,B=255,A=0) +C_OrthoBackground=(R=163,G=163,B=163,A=0) +C_Current=(R=0,G=0,B=0,A=0) +C_BrushVertex=(R=0,G=0,B=0,A=0) +C_BrushSnap=(R=0,G=0,B=0,A=0) +C_Black=(R=0,G=0,B=0,A=0) +C_Mask=(R=0,G=0,B=0,A=0) +C_WireBackground=(R=0,G=0,B=0,A=0) +C_ZoneWire=(R=0,G=0,B=0,A=0) +EditPackages=Core +EditPackages=Engine +EditPackages=Editor +EditPackages=UWindow +EditPackages=Fire +EditPackages=IpDrv +EditPackages=UWeb +EditPackages=UBrowser +EditPackages=UnrealShare +EditPackages=UnrealI +EditPackages=UMenu +EditPackages=IpServer +EditPackages=Botpack +EditPackages=UTServerAdmin +EditPackages=UTMenu +EditPackages=UTBrowser + +[UMenu.UnrealConsole] +RootWindow=UMenu.UMenuRootWindow +UWindowKey=IK_Esc +ShowDesktop=True + +[UMenu.UMenuMenuBar] +ShowHelp=True +GameUMenuDefault=UTMenu.UTGameMenu +MultiplayerUMenuDefault=UTMenu.UTMultiplayerMenu +OptionsUMenuDefault=UTMenu.UTOptionsMenu + +[Botpack.ChallengeBotInfo] +Difficulty=1 + +[Botpack.DeathMatchPlus] +bNoviceMode=True +bHardCoreMode=True +bUseTranslocator=False +bCoopWeaponMode=False + +[Botpack.CTFGame] +bUseTranslocator=True +bCoopWeaponMode=True +GoalTeamScore=3 + +[Botpack.Domination] +bDumbDown=True +bUseTranslocator=True +bCoopWeaponMode=True +GoalTeamScore=100 + +[Botpack.Assault] +bUseTranslocator=False +bCoopWeaponMode=True + +[Botpack.TeamGamePlus] +bBalanceTeams=True +GoalTeamScore=30 +bPlayersBalanceTeams=True + +[Engine.GameInfo] +bLowGore=False +bVeryLowGore=False + +[UnrealShare.UnrealGameOptionsMenu] +bCanModifyGore=True + +[UBrowser.UBrowserMainClientWindow] +LANTabName=UBrowserLAN +ServerListNames[0]=UBrowserUT +ServerListNames[1]=UBrowserLAN +ServerListNames[2]=UBrowserPopulated +ServerListNames[3]=UBrowserDeathmatch +ServerListNames[4]=UBrowserTeamGames +ServerListNames[5]=UBrowserCTF +ServerListNames[6]=UBrowserDOM +ServerListNames[7]=UBrowserAS +ServerListNames[8]=UBrowserLMS +ServerListNames[9]=UBrowserAll +ServerListNames[10]=None +ServerListNames[11]=None +ServerListNames[12]=None +ServerListNames[13]=None +ServerListNames[14]=None +ServerListNames[15]=None +ServerListNames[16]=None +ServerListNames[17]=None +ServerListNames[18]=None +ServerListNames[19]=None + +[UBrowserUT] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,bCompatibleServersOnly=True + +[UBrowserLAN] +ListFactories[0]=UBrowser.UBrowserLocalFact,BeaconProduct=ut +URLAppend=?LAN +AutoRefreshTime=10 +bNoAutoSort=True + +[UBrowserPopulated] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,MinPlayers=1,bCompatibleServersOnly=True + +[UBrowserDeathmatch] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,GameType=DeathMatchPlus,bCompatibleServersOnly=True + +[UBrowserTeamGames] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,GameType=TeamGamePlus,bCompatibleServersOnly=True + +[UBrowserCTF] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,GameType=CTFGame,bCompatibleServersOnly=True + +[UBrowserDOM] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,GameType=Domination,bCompatibleServersOnly=True + +[UBrowserAS] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,GameType=Assault,bCompatibleServersOnly=True + +[UBrowserLMS] +ListFactories[0]=UBrowser.UBrowserSubsetFact,SupersetTag=UBrowserAll,GameType=LastManStanding,bCompatibleServersOnly=True + +[UBrowserAll] +ListFactories[0]=UBrowser.UBrowserGSpyFact,MasterServerAddress=unreal.epicgames.com,MasterServerTCPPort=28900,Region=0,GameName=ut +ListFactories[1]=UBrowser.UBrowserGSpyFact,MasterServerAddress=master0.gamespy.com,MasterServerTCPPort=28900,Region=0,GameName=ut +bHidden=True +bFallbackFactories=True + +[UTMenu.UTMultiplayerMenu] +OnlineServices[0]=LOCALIZE,MPlayer +OnlineServices[1]=LOCALIZE,Heat +OnlineServices[2]=LOCALIZE,WON + +[UTMenu.UTLadder] +bGOTY=true + +[UWeb.WebServer] +Applications[0]=UTServerAdmin.UTServerAdmin +ApplicationPaths[0]=/ServerAdmin +Applications[1]=UTServerAdmin.UTImageServer +ApplicationPaths[1]=/images +DefaultApplication=0 +bEnabled=False + +[UBrowser.UBrowserHTTPClient] +ProxyServerAddress= +ProxyServerPort= + +[UTServerAdmin.UTServerAdmin] +AdminUsername=admin +AdminPassword=admin diff --git a/dist.linux/ll-tests/gamesvr-ut99.sh b/dist.linux/ll-tests/gamesvr-ut99.sh new file mode 100644 index 0000000..fca5e32 --- /dev/null +++ b/dist.linux/ll-tests/gamesvr-ut99.sh @@ -0,0 +1,174 @@ +#!/bin/bash -i + +##################################################################################################### +### CONFIG VARS ##################################################################################### +declare LLTEST_CMD="/app/ucc server DM-Deck16][.unr?Game=Botpack.DeathMatchPlus -nohomedir -lanplay"; +declare LLTEST_NAME="gamesvr-csgo-$(date '+%H%M%S')"; +##################################################################################################### +##################################################################################################### + +# Runtime vars +declare LLCOUNTER=0; +declare LLBOOT_ERRORS=""; +declare LLTEST_HASFAILURES=false; +declare LLTEST_LOGFILE="$LLTEST_NAME"".log"; +declare LLTEST_RESULTSFILE="$LLTEST_NAME"".results"; + +# Server log file should contain $1 because $2 +function should_have() { + if ! grep -i -q "$1" "$LLTEST_LOGFILE"; then + echo $"[FAIL] - '$2'" >> "$LLTEST_RESULTSFILE"; + LLTEST_HASFAILURES=true; + else + echo $"[PASS] - '$2'" >> "$LLTEST_RESULTSFILE"; + fi; +} + +# Server log file should NOT contain $1 because $2 +function should_lack() { + if grep -i -q "$1" "$LLTEST_LOGFILE"; then + echo $"[FAIL] - '$2'" >> "$LLTEST_RESULTSFILE"; + LLTEST_HASFAILURES=true; + else + echo $"[PASS] - '$2'" >> "$LLTEST_RESULTSFILE"; + fi; +} + +# Command $1 should make server return $2 +function should_echo() { + tmux has-session -t "$LLTEST_NAME" 2>/dev/null; + if [ "$?" == 0 ] ; then + LLCOUNTER=0; + LLTMP=$(md5sum "$LLTEST_LOGFILE"); + tmux send -t "$LLTEST_NAME" C-z "$1" Enter; + + while true; do + sleep 0.5; + + if (( "$LLCOUNTER" > 30)); then + echo $"[FAIL] - Command '$!' TIMED OUT"; + LLTEST_HASFAILURES=true; + break; + fi; + + if [[ $(md5sum "$LLTEST_LOGFILE") != "$LLTMP" ]]; then + should_have "$2" "'$1' should result in '$2' (loop iterations: $LLCOUNTER)"; + break; + fi; + + (( LLCOUNTER++ )); + done; + else + echo $"[ERROR]- Could not run command '$1'; tmux session not found" >> "$LLTEST_RESULTSFILE"; + LLTEST_HASFAILURES=true; + fi; +} + +function print_log() { + if [ ! -s "$LLTEST_LOGFILE" ]; then + echo $'\nOUTPUT LOG IS EMPTY!\n'; + exit 1; + else + echo $'\n[LOGFILE OUTPUT]'; + awk '{print "»» " $0}' "$LLTEST_LOGFILE"; + fi; +} + +# Check prereqs +command -v awk > /dev/null 2>&1 || echo "awk is missing"; +command -v md5sum > /dev/null 2>&1 || echo "md5sum is missing"; +command -v sleep > /dev/null 2>&1 || echo "sleep is missing"; +command -v tmux > /dev/null 2>&1 || echo "tmux is missing"; + +# Prep log file +: > "$LLTEST_LOGFILE" +if [ ! -f "$LLTEST_LOGFILE" ]; then + echo 'Failed to create logfile: '"$LLTEST_LOGFILE"'. Verify file system permissions.'; + exit 2; +fi; + +# Prep results file +: > "$LLTEST_RESULTSFILE" +if [ ! -f "$LLTEST_RESULTSFILE" ]; then + echo 'Failed to create logfile: '"$LLTEST_RESULTSFILE"'. Verify file system permissions.'; + exit 2; +fi; + +echo $'\n\nRUNNING TEST: '"$LLTEST_NAME"; +echo $'Command: '"$LLTEST_CMD"; +echo "Running under $(id)"$'\n'; + +# Execute test command in tmux session +tmux new -d -s "$LLTEST_NAME" "sleep 0.5; $LLTEST_CMD"; +sleep 0.3; +tmux pipe-pane -t "$LLTEST_NAME" -o "cat > $LLTEST_LOGFILE"; + +while true; do + tmux has-session -t "$LLTEST_NAME" 2>/dev/null; + if [ "$?" != 0 ] ; then + echo $'terminated.\n'; + LLBOOT_ERRORS="Test process self-terminated"; + break; + fi; + + if (( "$LLCOUNTER" >= 19 )); then + if [ -s "$LLTEST_LOGFILE" ] && ((( $(date +%s) - $(stat -L --format %Y "$LLTEST_LOGFILE") ) > 10 )); then + echo $'succeeded.\n'; + break; + fi; + + if (( "$LLCOUNTER" > 120 )); then + echo $'timed out.\n'; + LLBOOT_ERRORS="Test timed out"; + break; + fi; + fi; + + if (( LLCOUNTER % 5 == 0 )); then + echo -n "$LLCOUNTER..."; + fi; + + (( LLCOUNTER++ )); + sleep 1; +done; + +if [ ! -s "$LLTEST_LOGFILE" ]; then + echo $'\nOUTPUT LOG IS EMPTY!\n'; + exit 1; +fi; + +if [ ! -z "${LLBOOT_ERRORS// }" ]; then + echo "Boot error: $LLBOOT_ERRORS"; + print_log; + exit 1; +fi; + +##################################################################################################### +### TESTS ########################################################################################### +should_lack "Couldn't run ucc (ucc-bin)" '/app/System/ucc-bin is executable'; +should_lack 'ucc-bin: not found' 'has dependency lib32z1/ia32-libs on x64'; +should_lack "Failed to load 'Level" 'able to load starting map'; +should_have 'Unreal engine initialized' 'engine was able to initialize'; +should_have 'Level is Level DM-Deck16\]\[.MyLevel' 'map loaded successfully'; +should_have 'Game engine initialized' 'game world started'; +##################################################################################################### +##################################################################################################### + +tmux has-session -t "$LLTEST_NAME" 2>/dev/null; +if [ "$?" == 0 ] ; then + tmux kill-session -t "$LLTEST_NAME"; +fi; + +print_log; + +echo $'\n[TEST RESULTS]\n'; +cat "$LLTEST_RESULTSFILE"; + +echo $'\n[OUTCOME]\n'; +if [ $LLTEST_HASFAILURES = true ]; then + echo $'Checks have failures!\n\n'; + exit 1; +fi; + +echo $'All checks passed!\n\n'; +exit 0; diff --git a/linux.Dockerfile b/linux.Dockerfile new file mode 100644 index 0000000..3f20ff2 --- /dev/null +++ b/linux.Dockerfile @@ -0,0 +1,62 @@ +# escape=` +ARG CONTAINER_REGISTRY="docker.io" + +FROM $CONTAINER_REGISTRY/lacledeslan/steamcmd:linux as ut99-builder + +ARG contentServer=content.lacledeslan.net + +RUN echo "Downloading UT99 Dedicated Server Assets" &&` + mkdir --parents /tmp/ &&` + curl -sSL "http://${contentServer}/fastDownloads/_installers/ut99-451-linux.7z" -o /tmp/ut99-server.7z &&` + echo "Validating download against known hash" &&` + echo "1f72326595e34474a955dfce7201c58ff16b772cb79ac118d3914d029b5e593e /tmp/ut99-server.7z" | sha256sum -c - &&` + echo "Extracting UT99 Dedicated Server Assets" &&` + 7z x -o/output/ /tmp/ut99-server.7z &&` + rm -f /tmp/*.7z + +#======================================================================= +FROM debian:bullseye-slim + +HEALTHCHECK NONE + +ARG BUILDNODE=unspecified +ARG SOURCE_COMMIT=unspecified + +RUN apt-get update && apt-get install -y ` + ca-certificates lib32z1 locales locales-all tmux &&` + apt-get clean &&` + echo "LC_ALL=en_US.UTF-8" >> /etc/environment &&` + rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*; + +ENV LANG=en_US.UTF-8 ` + LANGUAGE=en_US.UTF-8 ` + LC_ALL=en_US.UTF-8 ` + UT_DATA_PATH=/app/System + +LABEL com.lacledeslan.build-node=$BUILDNODE ` + org.opencontainers.image.source=https://github.com/lacledeslan/gamesvr-ut99 ` + org.opencontainers.image.title="Unreal Tournament 99 Dedicated Server" ` + org.opencontainers.image.url=https://github.com/LacledesLAN/README.1ST ` + org.opencontainers.image.vendor="Laclede's LAN" ` + org.opencontainers.image.version=$SOURCE_COMMIT + +# Set up Enviornment +RUN useradd --home /app --gid root --system UT99 &&` + mkdir -p /app &&` + chown UT99:root -R /app; + +COPY --chown=UT99:root --from=ut99-builder /output /app + +RUN chmod +x /app/checkfiles.sh /app/ucc /app/System/ucc-bin + +COPY --chown=UT99:root /dist.linux/ /app/ + +RUN chmod +x /app/ll-tests/*.sh + +USER UT99 + +WORKDIR /app + +CMD ["/bin/bash"] + +ONBUILD USER root