mirror of
https://github.com/citizenfx/cfx-server-data.git
synced 2025-01-08 22:22:57 +08:00
work on __resource -> fxmanifest and RDR compatibility
This commit is contained in:
parent
4fff23e2ff
commit
5ca4612547
@ -1,3 +1,6 @@
|
|||||||
resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } }
|
resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } }
|
||||||
|
|
||||||
map 'map.lua'
|
map 'map.lua'
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
game 'gta5'
|
@ -1,3 +1,6 @@
|
|||||||
resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } }
|
resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } }
|
||||||
|
|
||||||
map 'map.lua'
|
map 'map.lua'
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
game 'gta5'
|
8
resources/[gamemodes]/[maps]/redm-map-one/fxmanifest.lua
Normal file
8
resources/[gamemodes]/[maps]/redm-map-one/fxmanifest.lua
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } }
|
||||||
|
|
||||||
|
map 'map.lua'
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
game 'rdr3'
|
||||||
|
|
||||||
|
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
|
2
resources/[gamemodes]/[maps]/redm-map-one/map.lua
Normal file
2
resources/[gamemodes]/[maps]/redm-map-one/map.lua
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
spawnpoint 'player_three' { x = -262.849, y = 793.404, z = 118.087 }
|
||||||
|
spawnpoint 'player_zero' { x = -262.849, y = 793.404, z = 118.087 }
|
@ -1,3 +0,0 @@
|
|||||||
resource_type 'gametype' { name = 'Freeroam' }
|
|
||||||
|
|
||||||
client_script 'basic_client.lua'
|
|
6
resources/[gamemodes]/basic-gamemode/fxmanifest.lua
Normal file
6
resources/[gamemodes]/basic-gamemode/fxmanifest.lua
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
resource_type 'gametype' { name = 'Freeroam' }
|
||||||
|
|
||||||
|
client_script 'basic_client.lua'
|
||||||
|
|
||||||
|
game 'common'
|
||||||
|
fx_version 'adamant'
|
@ -8,3 +8,6 @@ chat_theme 'gtao' {
|
|||||||
default = '<b>{0}</b><span>{1}</span>'
|
default = '<b>{0}</b><span>{1}</span>'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game 'common'
|
||||||
|
fx_version 'adamant'
|
@ -3,10 +3,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chat-window {
|
.chat-window {
|
||||||
--size: calc((((2.7vw / 1.77777) * 1.2)) * 6);
|
--size: calc(((2.7vh * 1.2)) * 6);
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: calc(1.56vw);
|
right: calc(2.77vh);
|
||||||
top: calc(50% - (var(--size) / 2));
|
top: calc(50% - (var(--size) / 2));
|
||||||
height: var(--size) !important;
|
height: var(--size) !important;
|
||||||
|
|
||||||
@ -33,10 +33,10 @@
|
|||||||
font-family: Font2, sans-serif;
|
font-family: Font2, sans-serif;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
font-size: calc(1.8vw / 1.77777); /* 13px in 720p, calc'd by width */
|
font-size: calc(1.8vh); /* 13px in 720p, calc'd by width */
|
||||||
filter: url(#svgDropShadowFilter);
|
filter: url(#svgDropShadowFilter);
|
||||||
|
|
||||||
line-height: calc((2.7vw / 1.77777) * 1.2);
|
line-height: calc(2.7vh * 1.2);
|
||||||
|
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
|
||||||
font-size: calc(2.7vw / 1.77777); /* 13px in 720p, calc'd by width */
|
font-size: calc(2.7vh);
|
||||||
}
|
}
|
||||||
|
|
||||||
.msg > span > span > span {
|
.msg > span > span > span {
|
||||||
@ -69,8 +69,8 @@
|
|||||||
|
|
||||||
.chat-input {
|
.chat-input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: calc(1.56vw);
|
right: calc(2.77vh);
|
||||||
bottom: calc(1.56vw);
|
bottom: calc(2.77vh);
|
||||||
|
|
||||||
background: inherit !important;
|
background: inherit !important;
|
||||||
|
|
||||||
@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
.chat-input > div {
|
.chat-input > div {
|
||||||
background-color: rgba(0, 0, 0, .6);
|
background-color: rgba(0, 0, 0, .6);
|
||||||
padding: calc(0.15625vw / 2);
|
padding: calc(0.28vh / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input .prefix {
|
.chat-input .prefix {
|
||||||
@ -97,20 +97,32 @@
|
|||||||
|
|
||||||
.chat-input > div + div {
|
.chat-input > div + div {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: calc(1.65vh + 0.15625vw + 0.15625vw + 0.15625vw + (0.15625vw / 2));
|
bottom: calc(1.65vh + 0.28vh + 0.28vh + 0.28vh + (0.28vh / 2));
|
||||||
width: 99.6%;
|
width: 99.6%;
|
||||||
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.suggestions {
|
.suggestions {
|
||||||
border: calc(0.15625vw / 2) solid rgba(180, 180, 180, .6);
|
border: calc(0.28vh / 2) solid rgba(180, 180, 180, .6);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: calc(0.15625vw / 2) solid rgba(180, 180, 180, .6);
|
border: calc(0.28vh / 2) solid rgba(180, 180, 180, .6);
|
||||||
padding: calc(0.15625vw / 2);
|
padding: calc(0.28vh / 2);
|
||||||
padding-left: calc(3.5% + (0.15625vw / 2));
|
padding-left: calc(3.5% + (0.28vh / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-aspect-ratio: 21/9) {
|
||||||
|
.chat-window, .chat-input {
|
||||||
|
right: calc(12.8vw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-aspect-ratio: 32/9) {
|
||||||
|
.chat-window, .chat-input {
|
||||||
|
right: calc(25vw);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
local isRDR = not TerraingridActivate and true or false
|
||||||
|
|
||||||
local chatInputActive = false
|
local chatInputActive = false
|
||||||
local chatInputActivating = false
|
local chatInputActivating = false
|
||||||
local chatHidden = true
|
local chatHidden = true
|
||||||
@ -194,7 +196,7 @@ Citizen.CreateThread(function()
|
|||||||
Wait(0)
|
Wait(0)
|
||||||
|
|
||||||
if not chatInputActive then
|
if not chatInputActive then
|
||||||
if IsControlPressed(0, 245) --[[ INPUT_MP_TEXT_CHAT_ALL ]] then
|
if IsControlPressed(0, isRDR and `INPUT_MP_TEXT_CHAT_ALL` or 245) --[[ INPUT_MP_TEXT_CHAT_ALL ]] then
|
||||||
chatInputActive = true
|
chatInputActive = true
|
||||||
chatInputActivating = true
|
chatInputActivating = true
|
||||||
|
|
||||||
@ -205,7 +207,7 @@ Citizen.CreateThread(function()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if chatInputActivating then
|
if chatInputActivating then
|
||||||
if not IsControlPressed(0, 245) then
|
if not IsControlPressed(0, isRDR and `INPUT_MP_TEXT_CHAT_ALL` or 245) then
|
||||||
SetNuiFocus(true)
|
SetNuiFocus(true)
|
||||||
|
|
||||||
chatInputActivating = false
|
chatInputActivating = false
|
||||||
|
@ -24,3 +24,7 @@ files {
|
|||||||
'html/vendor/fonts/LatoBold.woff2',
|
'html/vendor/fonts/LatoBold.woff2',
|
||||||
'html/vendor/fonts/LatoBold2.woff2',
|
'html/vendor/fonts/LatoBold2.woff2',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
games { 'rdr3', 'gta5' }
|
||||||
|
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
|
@ -24,4 +24,5 @@ files {
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- support the latest resource manifest
|
-- support the latest resource manifest
|
||||||
resource_manifest_version '05cfa83c-a124-4cfa-a768-c24a5811d8f9'
|
fx_version 'adamant'
|
||||||
|
game 'gta5'
|
@ -8,7 +8,8 @@ server_scripts {
|
|||||||
"mapmanager_server.lua"
|
"mapmanager_server.lua"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource_manifest_version "77731fab-63ca-442c-a67b-abc70f28dfa5"
|
fx_version 'adamant'
|
||||||
|
games { 'gta5', 'rdr3' }
|
||||||
|
|
||||||
server_export "getCurrentGameType"
|
server_export "getCurrentGameType"
|
||||||
server_export "getCurrentMap"
|
server_export "getCurrentMap"
|
||||||
@ -17,3 +18,5 @@ server_export "changeMap"
|
|||||||
server_export "doesMapSupportGameType"
|
server_export "doesMapSupportGameType"
|
||||||
server_export "getMaps"
|
server_export "getMaps"
|
||||||
server_export "roundEnded"
|
server_export "roundEnded"
|
||||||
|
|
||||||
|
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
|
@ -62,6 +62,10 @@ AddEventHandler('onResourceStop', function(res)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
AddEventHandler('getMapDirectives', function(add)
|
AddEventHandler('getMapDirectives', function(add)
|
||||||
|
if not CreateScriptVehicleGenerator then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
add('vehicle_generator', function(state, name)
|
add('vehicle_generator', function(state, name)
|
||||||
return function(opts)
|
return function(opts)
|
||||||
local x, y, z, heading
|
local x, y, z, heading
|
||||||
|
@ -8,3 +8,8 @@ export 'loadSpawns'
|
|||||||
export 'setAutoSpawn'
|
export 'setAutoSpawn'
|
||||||
export 'setAutoSpawnCallback'
|
export 'setAutoSpawnCallback'
|
||||||
export 'forceRespawn'
|
export 'forceRespawn'
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
games { 'rdr3', 'gta5' }
|
||||||
|
|
||||||
|
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
|
@ -187,6 +187,10 @@ local function freezePlayer(id, freeze)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function loadScene(x, y, z)
|
function loadScene(x, y, z)
|
||||||
|
if not NewLoadSceneStart then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
NewLoadSceneStart(x, y, z, 0.0, 0.0, 0.0, 20.0, 0)
|
NewLoadSceneStart(x, y, z, 0.0, 0.0, 0.0, 20.0, 0)
|
||||||
|
|
||||||
while IsNewLoadSceneActive() do
|
while IsNewLoadSceneActive() do
|
||||||
@ -258,14 +262,18 @@ function spawnPlayer(spawnIdx, cb)
|
|||||||
|
|
||||||
-- release the player model
|
-- release the player model
|
||||||
SetModelAsNoLongerNeeded(spawn.model)
|
SetModelAsNoLongerNeeded(spawn.model)
|
||||||
|
|
||||||
|
-- RDR3 player model bits
|
||||||
|
if N_0x283978a15512b2fe then
|
||||||
|
N_0x283978a15512b2fe(PlayerPedId(), true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- preload collisions for the spawnpoint
|
-- preload collisions for the spawnpoint
|
||||||
RequestCollisionAtCoord(spawn.x, spawn.y, spawn.z)
|
RequestCollisionAtCoord(spawn.x, spawn.y, spawn.z)
|
||||||
|
|
||||||
-- spawn the player
|
-- spawn the player
|
||||||
--ResurrectNetworkPlayer(GetPlayerId(), spawn.x, spawn.y, spawn.z, spawn.heading)
|
local ped = PlayerPedId()
|
||||||
local ped = GetPlayerPed(-1)
|
|
||||||
|
|
||||||
-- V requires setting coords as well
|
-- V requires setting coords as well
|
||||||
SetEntityCoordsNoOffset(ped, spawn.x, spawn.y, spawn.z, false, false, false, true)
|
SetEntityCoordsNoOffset(ped, spawn.x, spawn.y, spawn.z, false, false, false, true)
|
||||||
@ -328,7 +336,7 @@ Citizen.CreateThread(function()
|
|||||||
while true do
|
while true do
|
||||||
Citizen.Wait(50)
|
Citizen.Wait(50)
|
||||||
|
|
||||||
local playerPed = GetPlayerPed(-1)
|
local playerPed = PlayerPedId()
|
||||||
|
|
||||||
if playerPed and playerPed ~= -1 then
|
if playerPed and playerPed ~= -1 then
|
||||||
-- check if we want to autospawn
|
-- check if we want to autospawn
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
dependency 'yarn'
|
|
||||||
--server_only 'yes'
|
|
||||||
server_script 'webpack_builder.js'
|
|
5
resources/[system]/[builders]/webpack/fxmanifest.lua
Normal file
5
resources/[system]/[builders]/webpack/fxmanifest.lua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
dependency 'yarn'
|
||||||
|
server_script 'webpack_builder.js'
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
game 'common'
|
@ -1,2 +0,0 @@
|
|||||||
--server_only 'yes'
|
|
||||||
server_script 'yarn_builder.js'
|
|
4
resources/[system]/[builders]/yarn/fxmanifest.lua
Normal file
4
resources/[system]/[builders]/yarn/fxmanifest.lua
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fx_version 'adamant'
|
||||||
|
game 'common'
|
||||||
|
|
||||||
|
server_script 'yarn_builder.js'
|
@ -41,7 +41,7 @@ const yarnBuildTask = {
|
|||||||
currentBuildingModule = resourceName;
|
currentBuildingModule = resourceName;
|
||||||
const process = child_process.fork(
|
const process = child_process.fork(
|
||||||
require.resolve('./yarn_cli.js'),
|
require.resolve('./yarn_cli.js'),
|
||||||
['install'],
|
['install', '--ignore-scripts'],
|
||||||
{
|
{
|
||||||
cwd: path.resolve(GetResourcePath(resourceName))
|
cwd: path.resolve(GetResourcePath(resourceName))
|
||||||
});
|
});
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
client_script 'client.lua'
|
|
||||||
server_script 'server.lua'
|
|
6
resources/[system]/hardcap/fxmanifest.lua
Normal file
6
resources/[system]/hardcap/fxmanifest.lua
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
client_script 'client.lua'
|
||||||
|
server_script 'server.lua'
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
games { 'gta5', 'rdr3' }
|
||||||
|
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
|
@ -1,2 +0,0 @@
|
|||||||
client_script 'rconlog_client.lua'
|
|
||||||
server_script 'rconlog_server.lua'
|
|
7
resources/[system]/rconlog/fxmanifest.lua
Normal file
7
resources/[system]/rconlog/fxmanifest.lua
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
client_script 'rconlog_client.lua'
|
||||||
|
server_script 'rconlog_server.lua'
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
games { 'gta5', 'rdr3' }
|
||||||
|
|
||||||
|
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
|
@ -16,3 +16,6 @@ files {
|
|||||||
'html/res/futurastd-medium.ttf',
|
'html/res/futurastd-medium.ttf',
|
||||||
'html/res/futurastd-medium.svg',
|
'html/res/futurastd-medium.svg',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fx_version 'adamant'
|
||||||
|
game 'gta5'
|
@ -8,7 +8,7 @@ Citizen.CreateThread(function()
|
|||||||
if IsControlPressed(0, 27)--[[ INPUT_PHONE ]] then
|
if IsControlPressed(0, 27)--[[ INPUT_PHONE ]] then
|
||||||
if not listOn then
|
if not listOn then
|
||||||
local players = {}
|
local players = {}
|
||||||
ptable = GetPlayers()
|
local ptable = GetActivePlayers()
|
||||||
for _, i in ipairs(ptable) do
|
for _, i in ipairs(ptable) do
|
||||||
local wantedLevel = GetPlayerWantedLevel(i)
|
local wantedLevel = GetPlayerWantedLevel(i)
|
||||||
r, g, b = GetPlayerRgbColour(i)
|
r, g, b = GetPlayerRgbColour(i)
|
||||||
@ -35,18 +35,6 @@ Citizen.CreateThread(function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function GetPlayers()
|
|
||||||
local players = {}
|
|
||||||
|
|
||||||
for i = 0, 31 do
|
|
||||||
if NetworkIsPlayerActive(i) then
|
|
||||||
table.insert(players, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return players
|
|
||||||
end
|
|
||||||
|
|
||||||
function sanitize(txt)
|
function sanitize(txt)
|
||||||
local replacements = {
|
local replacements = {
|
||||||
['&' ] = '&',
|
['&' ] = '&',
|
||||||
|
2
resources/[system]/sessionmanager-rdr3/.gitignore
vendored
Normal file
2
resources/[system]/sessionmanager-rdr3/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
yarn.lock
|
8
resources/[system]/sessionmanager-rdr3/fxmanifest.lua
Normal file
8
resources/[system]/sessionmanager-rdr3/fxmanifest.lua
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fx_version 'adamant'
|
||||||
|
game 'common'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
'yarn'
|
||||||
|
}
|
||||||
|
|
||||||
|
server_script 'sm_server.js'
|
6
resources/[system]/sessionmanager-rdr3/package.json
Normal file
6
resources/[system]/sessionmanager-rdr3/package.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@citizenfx/protobufjs": "6.8.8"
|
||||||
|
}
|
||||||
|
}
|
169
resources/[system]/sessionmanager-rdr3/rline.proto
Normal file
169
resources/[system]/sessionmanager-rdr3/rline.proto
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package rline;
|
||||||
|
|
||||||
|
message RpcErrorData {
|
||||||
|
string ErrorCodeString = 1;
|
||||||
|
int32 ErrorCode = 2;
|
||||||
|
string DomainString = 3;
|
||||||
|
int32 DomainCode = 4;
|
||||||
|
bytes DataEx = 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
message RpcError {
|
||||||
|
int32 ErrorCode = 1;
|
||||||
|
string ErrorMessage = 2;
|
||||||
|
RpcErrorData Data = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
message RpcHeader {
|
||||||
|
string RequestId = 1;
|
||||||
|
string MethodName = 2;
|
||||||
|
RpcError Error = 3;
|
||||||
|
string srcTid = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
message RpcMessage {
|
||||||
|
RpcHeader Header = 1;
|
||||||
|
bytes Content = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
message RpcResponseContainer {
|
||||||
|
bytes Content = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message RpcResponseMessage {
|
||||||
|
RpcHeader Header = 1;
|
||||||
|
RpcResponseContainer Container = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
message TokenStuff {
|
||||||
|
string tkn = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message InitSessionResponse {
|
||||||
|
bytes sesid = 1;
|
||||||
|
TokenStuff token = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
message MpGamerHandleDto {
|
||||||
|
string gh = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message MpPeerAddressDto {
|
||||||
|
string addr = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message InitPlayer2_Parameters {
|
||||||
|
MpGamerHandleDto gh = 1;
|
||||||
|
MpPeerAddressDto peerAddress = 2;
|
||||||
|
int32 discriminator = 3;
|
||||||
|
int32 seamlessType = 4;
|
||||||
|
uint32 connectionReason = 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
message InitPlayerResult {
|
||||||
|
uint32 code = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message Restriction {
|
||||||
|
int32 u1 = 1;
|
||||||
|
int32 u2 = 2;
|
||||||
|
int32 u3 = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetRestrictionsData {
|
||||||
|
repeated Restriction restriction = 1;
|
||||||
|
repeated string unk2 = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
message GetRestrictionsResult {
|
||||||
|
GetRestrictionsData data = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message PlayerIdSto {
|
||||||
|
int32 acctId = 1;
|
||||||
|
int32 platId = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
message MpSessionRequestIdDto {
|
||||||
|
PlayerIdSto requestor = 1;
|
||||||
|
int32 index = 2;
|
||||||
|
int32 hash = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
message QueueForSession_Seamless_Parameters {
|
||||||
|
MpSessionRequestIdDto requestId = 1;
|
||||||
|
uint32 optionFlags = 2;
|
||||||
|
int32 x = 3;
|
||||||
|
int32 y = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
message QueueForSessionResult {
|
||||||
|
uint32 code = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message QueueEntered_Parameters {
|
||||||
|
uint32 queueGroup = 1;
|
||||||
|
MpSessionRequestIdDto requestId = 2;
|
||||||
|
uint32 optionFlags = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
message GuidDto {
|
||||||
|
fixed64 a = 1;
|
||||||
|
fixed64 b = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
message MpTransitionIdDto {
|
||||||
|
GuidDto value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message MpSessionIdDto {
|
||||||
|
GuidDto value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message SessionSubcommandEnterSession {
|
||||||
|
int32 index = 1;
|
||||||
|
int32 hindex = 2;
|
||||||
|
uint32 sessionFlags = 3;
|
||||||
|
uint32 mode = 4;
|
||||||
|
int32 size = 5;
|
||||||
|
int32 teamIndex = 6;
|
||||||
|
MpTransitionIdDto transitionId = 7;
|
||||||
|
uint32 sessionManagerType = 8;
|
||||||
|
int32 slotCount = 9;
|
||||||
|
};
|
||||||
|
|
||||||
|
message SessionSubcommandLeaveSession {
|
||||||
|
uint32 reason = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message SessionSubcommandAddPlayer {
|
||||||
|
PlayerIdSto id = 1;
|
||||||
|
MpGamerHandleDto gh = 2;
|
||||||
|
MpPeerAddressDto addr = 3;
|
||||||
|
int32 index = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
message SessionSubcommandRemovePlayer {
|
||||||
|
PlayerIdSto id = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message SessionSubcommandHostChanged {
|
||||||
|
int32 index = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
message SessionCommand {
|
||||||
|
uint32 cmd = 1;
|
||||||
|
string cmdname = 2;
|
||||||
|
SessionSubcommandEnterSession EnterSession = 3;
|
||||||
|
SessionSubcommandLeaveSession LeaveSession = 4;
|
||||||
|
SessionSubcommandAddPlayer AddPlayer = 5;
|
||||||
|
SessionSubcommandRemovePlayer RemovePlayer = 6;
|
||||||
|
SessionSubcommandHostChanged HostChanged = 7;
|
||||||
|
};
|
||||||
|
|
||||||
|
message scmds_Parameters {
|
||||||
|
MpSessionIdDto sid = 1;
|
||||||
|
int32 ncmds = 2;
|
||||||
|
repeated SessionCommand cmds = 3;
|
||||||
|
};
|
276
resources/[system]/sessionmanager-rdr3/sm_server.js
Normal file
276
resources/[system]/sessionmanager-rdr3/sm_server.js
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
const protobuf = require("@citizenfx/protobufjs");
|
||||||
|
|
||||||
|
const playerDatas = {};
|
||||||
|
let slotsUsed = 0;
|
||||||
|
|
||||||
|
function assignSlotId() {
|
||||||
|
for (let i = 0; i < 32; i++) {
|
||||||
|
if (!(slotsUsed & (1 << i))) {
|
||||||
|
slotsUsed |= (1 << i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hostIndex = -1;
|
||||||
|
|
||||||
|
protobuf.load(GetResourcePath(GetCurrentResourceName()) + "/rline.proto", function(err, root) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RpcMessage = root.lookupType("rline.RpcMessage");
|
||||||
|
const RpcResponseMessage = root.lookupType("rline.RpcResponseMessage");
|
||||||
|
const InitSessionResponse = root.lookupType("rline.InitSessionResponse");
|
||||||
|
const InitPlayer2_Parameters = root.lookupType("rline.InitPlayer2_Parameters");
|
||||||
|
const InitPlayerResult = root.lookupType("rline.InitPlayerResult");
|
||||||
|
const GetRestrictionsResult = root.lookupType("rline.GetRestrictionsResult");
|
||||||
|
const QueueForSession_Seamless_Parameters = root.lookupType("rline.QueueForSession_Seamless_Parameters");
|
||||||
|
const QueueForSessionResult = root.lookupType("rline.QueueForSessionResult");
|
||||||
|
const QueueEntered_Parameters = root.lookupType("rline.QueueEntered_Parameters");
|
||||||
|
const scmds_Parameters = root.lookupType("rline.scmds_Parameters");
|
||||||
|
|
||||||
|
function toArrayBuffer(buf) {
|
||||||
|
var ab = new ArrayBuffer(buf.length);
|
||||||
|
var view = new Uint8Array(ab);
|
||||||
|
for (var i = 0; i < buf.length; ++i) {
|
||||||
|
view[i] = buf[i];
|
||||||
|
}
|
||||||
|
return ab;
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitMsg(target, data) {
|
||||||
|
emitNet('__cfx_internal:pbRlScSession', target, toArrayBuffer(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitSessionCmds(target, cmd, cmdname, msg) {
|
||||||
|
const stuff = {};
|
||||||
|
stuff[cmdname] = msg;
|
||||||
|
|
||||||
|
emitMsg(target, RpcMessage.encode({
|
||||||
|
Header: {
|
||||||
|
MethodName: 'scmds'
|
||||||
|
},
|
||||||
|
Content: scmds_Parameters.encode({
|
||||||
|
sid: {
|
||||||
|
value: {
|
||||||
|
a: 2,
|
||||||
|
b: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ncmds: 1,
|
||||||
|
cmds: [
|
||||||
|
{
|
||||||
|
cmd,
|
||||||
|
cmdname,
|
||||||
|
...stuff
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).finish()
|
||||||
|
}).finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitAddPlayer(target, msg) {
|
||||||
|
emitSessionCmds(target, 2, 'AddPlayer', msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitRemovePlayer(target, msg) {
|
||||||
|
emitSessionCmds(target, 3, 'RemovePlayer', msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitHostChanged(target, msg) {
|
||||||
|
emitSessionCmds(target, 5, 'HostChanged', msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNet('playerDropped', () => {
|
||||||
|
try {
|
||||||
|
const oData = playerDatas[source];
|
||||||
|
delete playerDatas[source];
|
||||||
|
|
||||||
|
if (oData && hostIndex === oData.slot) {
|
||||||
|
const pda = Object.entries(playerDatas);
|
||||||
|
|
||||||
|
if (pda.length > 0) {
|
||||||
|
hostIndex = pda[0][1].slot | 0; // TODO: actually use <=31 slot index *and* check for id
|
||||||
|
|
||||||
|
for (const [ id, data ] of Object.entries(playerDatas)) {
|
||||||
|
emitHostChanged(id, {
|
||||||
|
index: hostIndex
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hostIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!oData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oData.slot > -1) {
|
||||||
|
slotsUsed &= ~(1 << oData.slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [ id, data ] of Object.entries(playerDatas)) {
|
||||||
|
emitRemovePlayer(id, {
|
||||||
|
id: oData.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
console.log(e.stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function makeResponse(type, data) {
|
||||||
|
return {
|
||||||
|
Header: {
|
||||||
|
},
|
||||||
|
Container: {
|
||||||
|
Content: type.encode(data).finish()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
async InitSession(source, data) {
|
||||||
|
return makeResponse(InitSessionResponse, {
|
||||||
|
sesid: Buffer.alloc(16),
|
||||||
|
/*token: {
|
||||||
|
tkn: 'ACSTOKEN token="meow",signature="meow"'
|
||||||
|
}*/
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async InitPlayer2(source, data) {
|
||||||
|
const req = InitPlayer2_Parameters.decode(data);
|
||||||
|
|
||||||
|
playerDatas[source] = {
|
||||||
|
gh: req.gh,
|
||||||
|
peerAddress: req.peerAddress,
|
||||||
|
discriminator: req.discriminator,
|
||||||
|
slot: -1
|
||||||
|
};
|
||||||
|
|
||||||
|
return makeResponse(InitPlayerResult, {
|
||||||
|
code: 0
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async GetRestrictions(source, data) {
|
||||||
|
return makeResponse(GetRestrictionsResult, {
|
||||||
|
data: {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async ConfirmSessionEntered(source, data) {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
|
async QueueForSession_Seamless(source, data) {
|
||||||
|
const req = QueueForSession_Seamless_Parameters.decode(data);
|
||||||
|
|
||||||
|
playerDatas[source].req = req.requestId;
|
||||||
|
playerDatas[source].id = req.requestId.requestor;
|
||||||
|
playerDatas[source].slot = assignSlotId();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
emitMsg(source, RpcMessage.encode({
|
||||||
|
Header: {
|
||||||
|
MethodName: 'QueueEntered'
|
||||||
|
},
|
||||||
|
Content: QueueEntered_Parameters.encode({
|
||||||
|
queueGroup: 69,
|
||||||
|
requestId: req.requestId,
|
||||||
|
optionFlags: req.optionFlags
|
||||||
|
}).finish()
|
||||||
|
}).finish());
|
||||||
|
|
||||||
|
if (hostIndex === -1) {
|
||||||
|
hostIndex = playerDatas[source].slot | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitSessionCmds(source, 0, 'EnterSession', {
|
||||||
|
index: playerDatas[source].slot | 0,
|
||||||
|
hindex: hostIndex,
|
||||||
|
sessionFlags: 0,
|
||||||
|
mode: 0,
|
||||||
|
size: Object.entries(playerDatas).filter(a => a[1].id).length,
|
||||||
|
//size: 2,
|
||||||
|
//size: Object.entries(playerDatas).length,
|
||||||
|
teamIndex: 0,
|
||||||
|
transitionId: {
|
||||||
|
value: {
|
||||||
|
a: 0,//2,
|
||||||
|
b: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sessionManagerType: 0,
|
||||||
|
slotCount: 32
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// tell player about everyone, and everyone about player
|
||||||
|
const meData = playerDatas[source];
|
||||||
|
|
||||||
|
const aboutMe = {
|
||||||
|
id: meData.id,
|
||||||
|
gh: meData.gh,
|
||||||
|
addr: meData.peerAddress,
|
||||||
|
index: playerDatas[source].slot | 0
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [ id, data ] of Object.entries(playerDatas)) {
|
||||||
|
if (id == source || !data.id) continue;
|
||||||
|
|
||||||
|
emitAddPlayer(source, {
|
||||||
|
id: data.id,
|
||||||
|
gh: data.gh,
|
||||||
|
addr: data.peerAddress,
|
||||||
|
index: data.slot | 0
|
||||||
|
});
|
||||||
|
|
||||||
|
emitAddPlayer(id, aboutMe);
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
return makeResponse(QueueForSessionResult, {
|
||||||
|
code: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async function handleMessage(source, method, data) {
|
||||||
|
if (handlers[method]) {
|
||||||
|
return await handlers[method](source, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
onNet('__cfx_internal:pbRlScSession', async (data) => {
|
||||||
|
const s = source;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const message = RpcMessage.decode(new Uint8Array(data));
|
||||||
|
const response = await handleMessage(s, message.Header.MethodName, message.Content);
|
||||||
|
|
||||||
|
if (!response || !response.Header) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Header.RequestId = message.Header.RequestId;
|
||||||
|
|
||||||
|
emitMsg(s, RpcResponseMessage.encode(response).finish());
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
console.log(e.stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user