mirror of
https://github.com/CyberL1/Minecraft-Realms-Emulator.git
synced 2025-06-30 17:19:43 -04:00
Compare commits
9 Commits
b0ed4a50de
...
master
Author | SHA1 | Date | |
---|---|---|---|
ff325cf5f6 | |||
484d12463a | |||
0a89b6ade1 | |||
967518dc71 | |||
1dc7194888 | |||
84548585ac | |||
f1a5ddd98c | |||
6cb43fcaa3 | |||
27a5d20888 |
@ -73,8 +73,8 @@ namespace Minecraft_Realms_Emulator.Modes.External
|
||||
OwnerUUID = world.OwnerUUID,
|
||||
Name = world.Name,
|
||||
Motd = world.Motd,
|
||||
GameMode = activeSlot.GameMode,
|
||||
IsHardcore = activeSlot.Difficulty == 3,
|
||||
GameMode = activeSlot?.GameMode ?? 0,
|
||||
IsHardcore = activeSlot?.Difficulty == 3,
|
||||
State = world.State,
|
||||
WorldType = world.WorldType,
|
||||
MaxPlayers = world.MaxPlayers,
|
||||
@ -177,8 +177,8 @@ namespace Minecraft_Realms_Emulator.Modes.External
|
||||
OwnerUUID = world.OwnerUUID,
|
||||
Name = world.Name,
|
||||
Motd = world.Motd,
|
||||
GameMode = activeSlot.GameMode,
|
||||
IsHardcore = activeSlot.Difficulty == 3,
|
||||
GameMode = activeSlot?.GameMode ?? 0,
|
||||
IsHardcore = activeSlot?.Difficulty == 3,
|
||||
State = world.State,
|
||||
WorldType = world.WorldType,
|
||||
MaxPlayers = world.MaxPlayers,
|
||||
@ -333,8 +333,8 @@ namespace Minecraft_Realms_Emulator.Modes.External
|
||||
OwnerUUID = world.OwnerUUID,
|
||||
Name = world.Name,
|
||||
Motd = world.Motd,
|
||||
GameMode = activeSlot.GameMode,
|
||||
IsHardcore = activeSlot.Difficulty == 3,
|
||||
GameMode = activeSlot?.GameMode ?? 0,
|
||||
IsHardcore = activeSlot?.Difficulty == 3,
|
||||
State = world.State,
|
||||
WorldType = world.WorldType,
|
||||
MaxPlayers = world.MaxPlayers,
|
||||
@ -610,15 +610,6 @@ namespace Minecraft_Realms_Emulator.Modes.External
|
||||
return Ok(world);
|
||||
}
|
||||
|
||||
[HttpPost("{wId}/reset")]
|
||||
[CheckForWorld]
|
||||
[CheckRealmOwner]
|
||||
public ActionResult<bool> Reset(int wId)
|
||||
{
|
||||
Console.WriteLine($"Resetting world {wId}");
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
[HttpPut("{wId}/open")]
|
||||
[CheckForWorld]
|
||||
[CheckRealmOwner]
|
||||
@ -690,126 +681,6 @@ namespace Minecraft_Realms_Emulator.Modes.External
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
[HttpPost("{wId}/slot/{sId}")]
|
||||
[CheckForWorld]
|
||||
[CheckRealmOwner]
|
||||
public async Task<ActionResult<(bool, ErrorResponse)>> UpdateSlot(int wId, int sId, SlotOptionsRequest body)
|
||||
{
|
||||
if (body.SlotName.Length > 10)
|
||||
{
|
||||
ErrorResponse errorResponse = new()
|
||||
{
|
||||
ErrorCode = 400,
|
||||
ErrorMsg = "Slot name cannot exceed 10 characters"
|
||||
};
|
||||
|
||||
return BadRequest(errorResponse);
|
||||
}
|
||||
|
||||
var slots = await _context.Slots.Where(s => s.World.Id == wId).ToListAsync();
|
||||
var slot = slots.Find(s => s.SlotId == sId);
|
||||
|
||||
slot.SlotName = body.SlotName;
|
||||
slot.GameMode = body.GameMode;
|
||||
slot.Difficulty = body.Difficulty;
|
||||
slot.SpawnProtection = body.SpawnProtection;
|
||||
slot.ForceGameMode = body.ForceGameMode;
|
||||
slot.Pvp = body.Pvp;
|
||||
slot.SpawnAnimals = body.SpawnAnimals;
|
||||
slot.SpawnMonsters = body.SpawnMonsters;
|
||||
slot.SpawnNPCs = body.SpawnNPCs;
|
||||
slot.CommandBlocks = body.CommandBlocks;
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
[HttpPut("{wId}/slot/{sId}")]
|
||||
[CheckForWorld]
|
||||
[CheckRealmOwner]
|
||||
public ActionResult<bool> SwitchSlot(int wId, int sId)
|
||||
{
|
||||
var world = _context.Worlds.Include(w => w.Minigame).FirstOrDefault(w => w.Id == wId);
|
||||
var slot = _context.Slots.Where(s => s.World.Id == wId).Where(s => s.SlotId == sId).Any();
|
||||
|
||||
if (!slot)
|
||||
{
|
||||
string cookie = Request.Headers.Cookie;
|
||||
string gameVersion = cookie.Split(";")[2].Split("=")[1];
|
||||
|
||||
_context.Slots.Add(new()
|
||||
{
|
||||
World = world,
|
||||
SlotId = sId,
|
||||
SlotName = "",
|
||||
Version = gameVersion,
|
||||
GameMode = 0,
|
||||
Difficulty = 2,
|
||||
SpawnProtection = 0,
|
||||
ForceGameMode = false,
|
||||
Pvp = true,
|
||||
SpawnAnimals = true,
|
||||
SpawnMonsters = true,
|
||||
SpawnNPCs = true,
|
||||
CommandBlocks = false
|
||||
});
|
||||
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
world.ActiveSlot = sId;
|
||||
world.Minigame = null;
|
||||
world.WorldType = nameof(WorldTypeEnum.NORMAL);
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
[HttpGet("{wId}/backups")]
|
||||
[CheckForWorld]
|
||||
[CheckRealmOwner]
|
||||
public async Task<ActionResult<BackupsResponse>> GetBackups(int wId)
|
||||
{
|
||||
var backups = await _context.Backups.Where(b => b.Slot.World.Id == wId).ToListAsync();
|
||||
|
||||
BackupsResponse worldBackups = new()
|
||||
{
|
||||
Backups = backups
|
||||
};
|
||||
|
||||
return Ok(worldBackups);
|
||||
}
|
||||
|
||||
[HttpGet("{wId}/slot/{sId}/download")]
|
||||
[CheckForWorld]
|
||||
[CheckRealmOwner]
|
||||
public ActionResult<BackupDownloadResponse> GetBackup(int wId, int sId)
|
||||
{
|
||||
Backup backup = _context.Backups.Include(b => b.Slot).FirstOrDefault(b => b.Slot.World.Id == wId && b.Slot.Id == sId);
|
||||
|
||||
if (backup == null)
|
||||
{
|
||||
ErrorResponse errorResponse = new()
|
||||
{
|
||||
ErrorCode = 404,
|
||||
ErrorMsg = "No backup found"
|
||||
};
|
||||
|
||||
return NotFound(errorResponse);
|
||||
}
|
||||
|
||||
BackupDownloadResponse backupDownloadResponse = new()
|
||||
{
|
||||
DownloadLink = backup.DownloadUrl,
|
||||
ResourcePackUrl = backup.ResourcePackUrl,
|
||||
ResourcePackHash = backup.ResourcePackHash,
|
||||
};
|
||||
|
||||
return Ok(backupDownloadResponse);
|
||||
}
|
||||
|
||||
[HttpGet("v1/{wId}/join/pc")]
|
||||
public ActionResult<Connection> Join(int wId)
|
||||
{
|
||||
@ -847,38 +718,5 @@ namespace Minecraft_Realms_Emulator.Modes.External
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
[HttpGet("templates/{type}")]
|
||||
public ActionResult<TemplatesResponse> GetWorldTemplates(string type, int page, int pageSize)
|
||||
{
|
||||
var totalTemplates = _context.Templates.Where(t => t.Type == type).Count();
|
||||
var templates = _context.Templates.Where(t => t.Type == type).Skip((page - 1) * pageSize).Take(pageSize).ToList();
|
||||
|
||||
TemplatesResponse templatesResponse = new()
|
||||
{
|
||||
Page = page,
|
||||
Size = pageSize,
|
||||
Total = totalTemplates,
|
||||
Templates = templates
|
||||
};
|
||||
|
||||
return Ok(templatesResponse);
|
||||
}
|
||||
|
||||
[HttpPut("minigames/{mId}/{wId}")]
|
||||
[CheckForWorld]
|
||||
[CheckRealmOwner]
|
||||
public ActionResult<bool> SwitchToMinigame(int mId, int wId)
|
||||
{
|
||||
var world = _context.Worlds.Find(wId);
|
||||
var minigame = _context.Templates.FirstOrDefault(t => t.Type == nameof(WorldTemplateTypeEnum.MINIGAME) && t.Id == mId);
|
||||
|
||||
world.Minigame = minigame;
|
||||
world.WorldType = nameof(WorldTypeEnum.MINIGAME);
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers
|
||||
OwnerUUID = world.OwnerUUID,
|
||||
Name = world.Name,
|
||||
Motd = world.Motd,
|
||||
GameMode = activeSlot.GameMode,
|
||||
IsHardcore = activeSlot.Difficulty == 3,
|
||||
GameMode = activeSlot?.GameMode ?? 0,
|
||||
IsHardcore = activeSlot?.Difficulty == 3,
|
||||
State = world.State,
|
||||
WorldType = world.WorldType,
|
||||
MaxPlayers = world.MaxPlayers,
|
||||
@ -180,8 +180,8 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers
|
||||
OwnerUUID = world.OwnerUUID,
|
||||
Name = world.Name,
|
||||
Motd = world.Motd,
|
||||
GameMode = activeSlot.GameMode,
|
||||
IsHardcore = activeSlot.Difficulty == 3,
|
||||
GameMode = activeSlot?.GameMode ?? 0,
|
||||
IsHardcore = activeSlot?.Difficulty == 3,
|
||||
State = world.State,
|
||||
WorldType = world.WorldType,
|
||||
MaxPlayers = world.MaxPlayers,
|
||||
@ -336,8 +336,8 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers
|
||||
OwnerUUID = world.OwnerUUID,
|
||||
Name = world.Name,
|
||||
Motd = world.Motd,
|
||||
GameMode = activeSlot.GameMode,
|
||||
IsHardcore = activeSlot.Difficulty == 3,
|
||||
GameMode = activeSlot?.GameMode ?? 0,
|
||||
IsHardcore = activeSlot?.Difficulty == 3,
|
||||
State = world.State,
|
||||
WorldType = world.WorldType,
|
||||
MaxPlayers = world.MaxPlayers,
|
||||
@ -687,6 +687,15 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
var connection = _context.Connections.FirstOrDefault(c => c.World.Id == wId);
|
||||
var query = new MinecraftServerQuery().Query(connection.Address);
|
||||
|
||||
while (query != null)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
query = new MinecraftServerQuery().Query(connection.Address);
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
@ -893,7 +902,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers
|
||||
[HttpGet("v1/{wId}/join/pc")]
|
||||
public async Task<ActionResult<Connection>> Join(int wId)
|
||||
{
|
||||
var connection = _context.Connections.Include(c => c.World).FirstOrDefault(x => x.World.Id == wId);
|
||||
var connection = _context.Connections.Include(c => c.World).Include(c => c.World.Slots).FirstOrDefault(x => x.World.Id == wId);
|
||||
|
||||
var isRunning = new DockerHelper(connection.World).IsRunning();
|
||||
var query = new MinecraftServerQuery().Query(connection.Address);
|
||||
@ -909,7 +918,17 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers
|
||||
query = new MinecraftServerQuery().Query(connection.Address);
|
||||
}
|
||||
|
||||
Slot activeSlot = connection.World.Slots.Find(s => s.SlotId == connection.World.ActiveSlot);
|
||||
|
||||
string cookie = Request.Headers.Cookie;
|
||||
string gameVersion = cookie.Split(";")[2].Split("=")[1];
|
||||
|
||||
if (new MinecraftVersionParser.MinecraftVersion(activeSlot.Version).CompareTo(new MinecraftVersionParser.MinecraftVersion(gameVersion)) < 0 && new DockerHelper(connection.World).RunCommand("! test -f .no-update") == 0)
|
||||
{
|
||||
activeSlot.Version = gameVersion;
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
string playerUUID = cookie.Split(";")[0].Split(":")[2];
|
||||
|
||||
if (connection.World.OwnerUUID == playerUUID)
|
||||
|
@ -68,7 +68,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Helpers
|
||||
ProcessStartInfo serverProcessInfo = new();
|
||||
|
||||
serverProcessInfo.FileName = "docker";
|
||||
serverProcessInfo.Arguments = $"container rm realm-server-{world.Id}";
|
||||
serverProcessInfo.Arguments = $"container rm -f realm-server-{world.Id}";
|
||||
|
||||
Process serverProcess = new();
|
||||
serverProcess.StartInfo = serverProcessInfo;
|
||||
@ -116,7 +116,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Helpers
|
||||
commandProcess.Start();
|
||||
}
|
||||
|
||||
public void RunCommand(string command)
|
||||
public int RunCommand(string command)
|
||||
{
|
||||
ProcessStartInfo commandProcessInfo = new();
|
||||
|
||||
@ -127,6 +127,9 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Helpers
|
||||
commandProcess.StartInfo = commandProcessInfo;
|
||||
|
||||
commandProcess.Start();
|
||||
commandProcess.WaitForExit();
|
||||
|
||||
return commandProcess.ExitCode;
|
||||
}
|
||||
}
|
||||
}
|
@ -33,6 +33,14 @@ builder.Services.AddDbContext<DataContext>(options =>
|
||||
options.UseNpgsql(dataSource);
|
||||
});
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddDefaultPolicy(policy =>
|
||||
{
|
||||
policy.WithOrigins("http://localhost:5192");
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Initialize database
|
||||
@ -48,10 +56,10 @@ if (app.Environment.IsDevelopment())
|
||||
var scope = app.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<DataContext>();
|
||||
|
||||
app.UseCors();
|
||||
app.MapControllers();
|
||||
|
||||
var config = new ConfigHelper(db);
|
||||
var mode = config.GetSetting(nameof(SettingsEnum.WorkMode));
|
||||
var mode = Environment.GetEnvironmentVariable("WORKMODE");
|
||||
|
||||
if (mode == null)
|
||||
{
|
||||
@ -59,13 +67,13 @@ if (mode == null)
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(typeof(WorkModeEnum), mode.Value))
|
||||
if (!Enum.IsDefined(typeof(WorkModeEnum), mode))
|
||||
{
|
||||
Console.WriteLine("Invalid server work mode, exiting");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
if (mode.Value == nameof(WorkModeEnum.REALMS))
|
||||
if (mode == nameof(WorkModeEnum.REALMS))
|
||||
{
|
||||
var resourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||
|
||||
@ -117,7 +125,7 @@ if (mode.Value == nameof(WorkModeEnum.REALMS))
|
||||
}
|
||||
}
|
||||
|
||||
var rewriteOptions = new RewriteOptions().AddRewrite(@"^(?!api)(.*)$", $"modes/{mode.Value}/$1", true);
|
||||
var rewriteOptions = new RewriteOptions().AddRewrite(@"^(?!api)(.*)$", $"modes/{mode}/$1", true);
|
||||
app.UseRewriter(rewriteOptions);
|
||||
|
||||
app.UseMiddleware<MinecraftCookieMiddleware>();
|
||||
@ -127,5 +135,5 @@ app.UseMiddleware<AdminKeyMiddleware>();
|
||||
app.UseMiddleware<CheckForWorldMiddleware>();
|
||||
app.UseMiddleware<RouteLoggingMiddleware>();
|
||||
|
||||
Console.WriteLine($"Running in {mode.Value} mode");
|
||||
Console.WriteLine($"Running in {mode} mode");
|
||||
app.Run();
|
||||
|
@ -3,7 +3,7 @@ FROM eclipse-temurin:21-jre-alpine
|
||||
COPY . .
|
||||
|
||||
RUN apk upgrade
|
||||
RUN apk add openssl
|
||||
RUN apk add openssl curl jq
|
||||
|
||||
RUN wget -O rcon-cli.tar.gz https://github.com/itzg/rcon-cli/releases/download/1.6.7/rcon-cli_1.6.7_linux_amd64.tar.gz
|
||||
RUN tar xzf rcon-cli.tar.gz
|
||||
@ -12,7 +12,6 @@ RUN rm rcon-cli.tar.gz
|
||||
RUN mv rcon-cli /bin/rcon-cli
|
||||
|
||||
WORKDIR mc
|
||||
RUN wget -O server.jar https://piston-data.mojang.com/v1/objects/450698d1863ab5180c25d7c804ef0fe6369dd1ba/server.jar
|
||||
|
||||
EXPOSE 25565
|
||||
|
||||
ENTRYPOINT ["/entrypoint"]
|
@ -11,4 +11,12 @@ if [ ! -f server.properties ]; then
|
||||
echo "level-name=slot-1" >> server.properties
|
||||
fi
|
||||
|
||||
# Download latest server.jar
|
||||
if [ ! -f .no-update ]; then
|
||||
VERSION_URL=$(curl https://piston-meta.mojang.com/mc/game/version_manifest_v2.json | jq -r '.latest.release as $latest | .versions | to_entries[] | select(.value.id == $latest) | .value.url')
|
||||
SERVER_URL=$(curl $VERSION_URL | jq -r .downloads.server.url)
|
||||
|
||||
wget -O server.jar $SERVER_URL
|
||||
fi
|
||||
|
||||
java -jar server.jar
|
@ -5,7 +5,6 @@
|
||||
NewsLink,
|
||||
DefaultServerAddress,
|
||||
TrialMode,
|
||||
WorkMode,
|
||||
OnlineMode,
|
||||
AutomaticRealmsCreation
|
||||
}
|
||||
|
@ -1,13 +1,10 @@
|
||||
using Minecraft_Realms_Emulator.Shared.Enums;
|
||||
|
||||
namespace Minecraft_Realms_Emulator.Shared.Helpers.Config
|
||||
namespace Minecraft_Realms_Emulator.Shared.Helpers.Config
|
||||
{
|
||||
public class Settings
|
||||
{
|
||||
public string DefaultServerAddress { get; set; } = "127.0.0.1";
|
||||
public string NewsLink { get; set; } = "https://github.com/CyberL1/Minecraft-Realms-Emulator";
|
||||
public bool TrialMode { get; set; } = true;
|
||||
public string WorkMode { get; set; } = nameof(WorkModeEnum.EXTERNAL);
|
||||
public bool OnlineMode { get; set; } = false;
|
||||
public bool AutomaticRealmsCreation { get; set; } = true;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
logs: "x",
|
||||
|
||||
start: (dotNetObject, serverId) => {
|
||||
logs = new EventSource(`http://localhost:8080/api/admin/servers/${serverId}/logs`, { withCredentials: true });
|
||||
logs = new EventSource(`http://localhost:8080/api/admin/servers/${serverId}/logs`);
|
||||
|
||||
logs.onmessage = event => {
|
||||
dotNetObject.invokeMethodAsync("ReceiveLog", event.data);
|
||||
|
Reference in New Issue
Block a user