I have the same exact problem described by the OP.
I removed some resources, including the mapmanager and the skater/hipster maps, and I’ve rewritten the code in C# in my gamemode project.
When I connect to my server, everything works as expected, however if I disconnect and then reconnect, the screen stays black.
My resources are
- this .NET gamemode script
- baseevents
- chat
- hardcap
- playernames
- rconlòg
- runcode
- scoreboard
- sessionmanager
In my Tick() event I have:
if (tickCount % 100 == 0)
{
var playerId = PlayerId();
var pedId = PlayerPedId();
// Spawning
if (pedId != -1 && NetworkIsPlayerActive(playerId))
{
if (PlayerState.ForceSkinSelection)
{
Log("Forcing the player to select a skin");
SkinSelector.EnterSkinSelection(); // code below
PlayerState.ForceSkinSelection = false;
}
else if (PlayerState.ForceRespawn
|| (deathTimestamp.HasValue && CheckTimePassed(deathTimestamp.Value, 8000)))
// CheckTimePassed is a method that returns whether the specified amount
// of ms have passed since the specified DateTime
// deathTimestamp is a Nullable<DateTime>
{
Log("Respawning the player");
Spawner.Spawn();
PlayerState.ForceRespawn = false;
deathTimestamp = null;
}
else if (deathTimestamp.HasValue && CheckTimePassed(deathTimestamp.Value, 4000))
{
SwitchOutPlayer(pedId, 0, 1);
}
}
if (IsEntityDead(pedId))
{
if (!deathTimestamp.HasValue)
{
deathTimestamp = DateTime.Now;
PlayerState.IsSpawned = false;
Log("Player died.");
}
}
else
{
deathTimestamp = null;
}
}
Relevant parts of SkinSelector
//
public static void EnterSkinSelection()
{
int playerId = PlayerId();
int pedId = PlayerPedId();
// freeze and hide the player ped during the loading
Log("Freezing and hiding the player ped.");
PlayerActions.Freeze(true); // code below
PlayerActions.Hide(true); // code below
// set to the first skin in the list
uint model = (uint)(CivilianSkins[0].PedHash); // CivilianSkins is a list of "Skin" objects, each containing a name and a PedHash
Log($"Setting player model ({CivilianSkins[0]})");
SetPlayerModel(playerId, model);
Log("Model was set");
//
Log("Requesting collision");
RequestCollisionAtCoord(pedPosition.X, pedPosition.Y, pedPosition.Z);
Log("Setting position");
SetEntityCoordsNoOffset(pedId, pedPosition.X, pedPosition.Y, pedPosition.Z, false, false, false);
NetworkResurrectLocalPlayer(pedPosition.X, pedPosition.Y, pedPosition.Z, pedPosition.W, true, true);
ResurrectPed(pedId);
Log("Spawned");
ClearPedTasksImmediately(pedId);
RemoveAllPedWeapons(pedId, false);
ClearPlayerWantedLevel(playerId);
var t = DateTime.Now;
while (!HasCollisionLoadedAroundEntity(pedId) && !CheckTimePassed(t, 5000))
Wait(100);
ShutdownLoadingScreen();
// create the selection camera
Log("Creating skin selection camera...");
camera = new Camera(CreateCam("DEFAULT_SCRIPTED_CAMERA", false));
camera.Position = camPosition;
camera.PointAt(new Vector3(pedPosition.X, pedPosition.Y, pedPosition.Z + 1f));
camera.IsActive = true;
RenderScriptCams(true, false, 0, true, false);
SetCamAffectsAiming(camera.Handle, true);
Log(" Camera created and activated");
//
PlayerActions.Hide(false);
// create the menu
menu = new Menu("Skin Selection", "Select your character skin");
foreach (var skin in CivilianSkins)
{
var item = new MenuItem(skin.Name);
item.ItemData = skin;
menu.AddMenuItem(item);
}
menu.OnMenuClose += OnMenuClose;
menu.OnIndexChange += OnMenuIndexChange;
menu.OnItemSelect += OnMenuItemSelect;
MenuController.AddMenu(menu);
MenuController.MenuAlignment = MenuController.MenuAlignmentOption.Right;
MenuController.MainMenu = menu;
menu.Visible = true;
//
Log("Skin selection is ready");
}
private static void OnMenuClose(Menu menu)
{
menu.Visible = true;
}
//
private static void OnMenuIndexChange(Menu menu, MenuItem oldItem, MenuItem newItem, int oldIndex, int newIndex)
{
if (newItem.ItemData is Skin skin)
{
int playerId = PlayerId();
uint model = (uint)(skin.PedHash);
Log($"Setting player model ({skin})");
SetPlayerModel(playerId, model);
}
}
//
private static void OnMenuItemSelect(Menu menu, MenuItem menuItem, int itemIndex)
{
if (camera != null)
{
RenderScriptCams(false, false, 0, true, false);
camera.Delete();
camera = null;
}
string description = "Skin";
if (menuItem.ItemData is Skin skin)
{
description = skin.ToString();
}
PlayerActions.Freeze(false);
DisplaySubtitle($"You selected ~r~{description}~s~!", 2000);
menu.Visible = false;
SwitchOutPlayer(PlayerPedId(), 0, 1);
Spawner.Spawn();
}
Freeze() and Hide()
public static void Freeze(bool freeze)
{
var player = PlayerId();
var ped = GetPlayerPed(player);
SetPlayerControl(player, !freeze, 0);
SetPlayerInvincible(player, freeze);
FreezeEntityPosition(ped, freeze);
if (freeze)
{
if (!IsPedFatallyInjured(ped))
ClearPedTasksImmediately(ped);
}
}
public static void Hide(bool hide)
{
var player = PlayerId();
var ped = GetPlayerPed(player);
SetEntityVisible(ped, !hide, true);
SetEntityCollision(ped, !hide, !hide);
}
Spawner.Spawn()
public static void Spawn()
{
//
int playerId = PlayerId();
int pedId = PlayerPedId();
//
Log($"Getting a random spawn point (count is {SpawnPoints.Count})");
var rIdx = GetRandom(SpawnPoints.Count);
Log($"rIdx is {rIdx}");
Vector4 spawn = SpawnPoints[rIdx];
Log($"Spawn: {spawn.X}, {spawn.Y}, {spawn.Z}, {spawn.W}");
Log("Requesting collision");
RequestCollisionAtCoord(spawn.X, spawn.Y, spawn.Z);
Log("Setting position");
SetEntityCoordsNoOffset(pedId, spawn.X, spawn.Y, spawn.Z, false, false, false);
NetworkResurrectLocalPlayer(spawn.X, spawn.Y, spawn.Z, spawn.W, true, true);
ResurrectPed(pedId);
Log("Spawned");
ClearPedTasksImmediately(pedId);
RemoveAllPedWeapons(pedId, false);
ClearPlayerWantedLevel(playerId);
Log("Switching in");
SwitchInPlayer(pedId);
PlayerState.IsSpawned = true;
}
In all scripts I have using static CitizenFX.Core.Native.API; to avoid having to type API. before every API call.