Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions KISSMultiplayer/lua/ge/extensions/kissghosts.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
local M = {}

M.global_state = {}
M.ghost_state = {}
M.overrides = {}

local actual_ghost_states = {}
local function set_vehicle_ghost(veh_id, ghost_state, mesh_fade, is_global)
ghost_state = ghost_state or 0
if M.overrides[veh_id] then
-- we still want M.ghost_state to keep its original value
ghost_state = M.overrides[veh_id]
else
M.ghost_state[veh_id] = ghost_state
end

if is_global then
M.global_state[veh_id] = ghost_state
end

if actual_ghost_states[veh_id] == ghost_state then return end
actual_ghost_states[veh_id] = ghost_state

local veh = getObjectByID(veh_id)
if ghost_state == 0 then -- no ghost
veh:setActive(1)
veh:queueLuaCommand("kiss_vehicle.set_collision(true)")
elseif ghost_state == 1 then -- no collisions
veh:setActive(1)
veh:queueLuaCommand("kiss_vehicle.set_collision(false)")
elseif ghost_state == 2 then -- in stasis (more logic for this state is in onUpdate)
veh:setActive(1)
veh:queueLuaCommand("kiss_vehicle.set_collision(false)")
elseif ghost_state == 3 then -- tucked somewhere in a parallel universe
veh:setActive(0)
end

if mesh_fade ~= nil then
if type(mesh_fade) ~= "number" then
mesh_fade = mesh_fade and 0.5 or 1
end
veh:setMeshAlpha(mesh_fade, "")
end
end

local bb_center_a, bb_half_axis0_a, bb_half_axis1_a, bb_half_axis2_a = vec3(), vec3(), vec3(), vec3()
local bb_center_b, bb_half_axis0_b, bb_half_axis1_b, bb_half_axis2_b = vec3(), vec3(), vec3(), vec3()

local function check_overlaps(vid_a)
bb_center_a:set(be:getObjectOOBBCenterXYZ(vid_a))
bb_half_axis0_a:set(be:getObjectOOBBHalfAxisXYZ(vid_a, 0))
bb_half_axis1_a:set(be:getObjectOOBBHalfAxisXYZ(vid_a, 1))
bb_half_axis2_a:set(be:getObjectOOBBHalfAxisXYZ(vid_a, 2))

local id_to_owner_map = vehiclemanager.id_to_owner_map
for vid_b in vehiclesIterator() do
if vid_a ~= vid_b and id_to_owner_map[vid_a] ~= id_to_owner_map[vid_b] then
bb_center_b:set(be:getObjectOOBBCenterXYZ(vid_b))
bb_half_axis0_b:set(be:getObjectOOBBHalfAxisXYZ(vid_b, 0))
bb_half_axis1_b:set(be:getObjectOOBBHalfAxisXYZ(vid_b, 1))
bb_half_axis2_b:set(be:getObjectOOBBHalfAxisXYZ(vid_b, 2))

if overlapsOBB_OBB(bb_center_a, bb_half_axis0_a, bb_half_axis1_a, bb_half_axis2_a,
bb_center_b, bb_half_axis0_b, bb_half_axis1_b, bb_half_axis2_b) then
return true
end
end
end

return false
end

local function set_respawn_override(vid, is_global)
if check_overlaps(vid) then
M.overrides[vid] = 1
else
M.overrides[vid] = nil
end

set_vehicle_ghost(vid, M.ghost_state[vid], M.overrides[vid] ~= nil, is_global)
end

local function set_pause_override(vid, override, is_global)
if override then
M.overrides[vid] = 2
elseif check_overlaps(vid) then
M.overrides[vid] = 1
else
M.overrides[vid] = nil
end

set_vehicle_ghost(vid, M.ghost_state[vid], M.overrides[vid] ~= nil, is_global)
end

local velocity = vec3()
local function set_pause_override_for_owned(bool)
for id in pairs(vehiclemanager.ownership) do
if bool then
local vehicle = getObjectByID(id)
velocity:set(vehicle:getVelocityXYZ())
if velocity:length() < 1 then
set_pause_override(id, true, true)
end
else
set_pause_override(id, false, true)
end
end
vehiclemanager.send_vehicle_meta_updates()
end

local function onUpdate()
for vid, v in pairs(actual_ghost_states) do
if v == 2 then
-- 0.75 appears to be a safe value
-- values too small cause breakage
local veh = getObjectByID(vid)
if veh and v then
veh:applyClusterVelocityScaleAdd(0, 0.75, 0, 0, 0)
end
end
end

for vid, v in pairs(M.overrides) do
if v == 1 then
set_respawn_override(vid, true)
end
end
end

local pause_counter = 0
local pause_requests = {}

local function attempt_pause(id)
if pause_requests[id] then
return
end
pause_requests[id] = true
pause_counter = pause_counter + 1
if pause_counter > 0 then
set_pause_override_for_owned(true)
SFXSystem.setGlobalParameter("g_GamePause", 1)
end
end

local function attempt_unpause(id)
if not pause_requests[id] then
return
end
pause_requests[id] = nil
pause_counter = math.max(0, pause_counter - 1)

if pause_counter == 0 then
set_pause_override_for_owned(false)
SFXSystem.setGlobalParameter("g_GamePause", 0)
end
end

local function onVehicleSpawned(veh_id)
-- because collisions are disabled vehicle side on respawn, this *must* update
actual_ghost_states[veh_id] = nil

set_respawn_override(veh_id, true)
end

local function onVehicleResetted(veh_id)
-- because collisions are disabled vehicle side on respawn, this *must* update
actual_ghost_states[veh_id] = nil

set_respawn_override(veh_id, true)
end

local function onVehicleDestroyed(vehId)
M.global_state[vehId] = nil
M.ghost_state[vehId] = nil
M.overrides[vehId] = nil
end

M.onUpdate = onUpdate
M.onVehicleDestroyed = onVehicleDestroyed
M.onVehicleSpawned = onVehicleSpawned
M.onVehicleResetted = onVehicleResetted

M.set_vehicle_ghost = set_vehicle_ghost
M.set_pause_override = set_pause_override
M.set_respawn_override = set_respawn_override

M.attempt_pause = attempt_pause
M.attempt_unpause = attempt_unpause

return M
26 changes: 26 additions & 0 deletions KISSMultiplayer/lua/ge/extensions/network.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ M.connection = {
time_offset = 0
}

local original_simTimeAuthorityFuncs = nil
-- pushPauseRequest
-- popPauseRequest

local blocked_inputs = {"slower_motion", "faster_motion", "toggle_slow_motion", "pause"}
local function block_inputs(block)
core_input_actionFilter.setGroup('kissmpActions', blocked_inputs)
core_input_actionFilter.addAction(0, 'kissmpActions', block)
end

local CHUNK_SIZE = 65000 -- Safe size under 65536 limit

local message_handlers = {}
Expand Down Expand Up @@ -121,6 +131,12 @@ local function disconnect(data)
if getMissionFilename() ~= "" then
returnToMainMenu()
end

if original_simTimeAuthorityFuncs then
simTimeAuthority.pushPauseRequest = original_simTimeAuthorityFuncs.pushPauseRequest
simTimeAuthority.popPauseRequest = original_simTimeAuthorityFuncs.popPauseRequest
end
block_inputs(false)
end

local function handle_player_info(player_info)
Expand Down Expand Up @@ -395,10 +411,20 @@ local function connect(addr, player_name, is_public)
end
end
vehiclemanager.loading_map = true

original_simTimeAuthorityFuncs = {
pushPauseRequest = simTimeAuthority.pushPauseRequest,
popPauseRequest = simTimeAuthority.popPauseRequest,
}

simTimeAuthority.pushPauseRequest = kissghosts.attempt_pause
simTimeAuthority.popPauseRequest = kissghosts.attempt_unpause

if #missing_mods == 0 then
kissmods.mount_mods(mod_names)
change_map(server_info.map)
end
block_inputs(true)
kissrichpresence.update()
kissui.chat.add_message("Connected!")
end
Expand Down
26 changes: 18 additions & 8 deletions KISSMultiplayer/lua/ge/extensions/vehiclemanager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ local generation = 0
local meta_timer = 0
local colors_buffer = {}
local plates_buffer = {}
local global_ghost_state_buffer = {}
local first_vehicle = true

M.loading_map = false
M.id_map = {}
M.server_ids = {}
M.ownership = {}
M.id_to_owner_map = {}
M.vehicle_updates_buffer = {}
M.packet_gen_buffer = {}
M.is_network_session = false
Expand Down Expand Up @@ -115,12 +117,19 @@ local function send_vehicle_meta_updates()
end
colors_buffer[id] = colors

local ghost_state = kissghosts.global_state[id] or 0
if global_ghost_state_buffer[id] then
changed = changed or global_ghost_state_buffer[id] ~= ghost_state
end
global_ghost_state_buffer[id] = ghost_state

if changed then
local data = {
VehicleMetaUpdate = {
id,
plate,
colors
colors,
ghost_state
}
}
network.send_data(data, true)
Expand Down Expand Up @@ -174,6 +183,7 @@ local function send_vehicle_config_inner(id, parts_config_json, buffer_data)
vehicle_data.rotation = {rotation.x, rotation.y, rotation.z, rotation.w}
vehicle_data.server_id = 0
vehicle_data.owner = 0
vehicle_data.global_ghost_state = 0
network.send_data(
{
VehicleData = vehicle_data
Expand Down Expand Up @@ -215,6 +225,7 @@ local function spawn_vehicle(data)
M.vehicle_buffer[data.server_id] = data
return
end
M.id_to_owner_map[data.in_game_id] = data.owner
if data.owner == network.get_client_id() then
log("I", "kissmp.vehiclemanager.spawn_vehicle", "Vehicle belongs to local client, setting ownership")
M.id_map[data.server_id] = data.in_game_id
Expand Down Expand Up @@ -436,6 +447,8 @@ local function update_vehicle_meta(data)
extensions.core_vehicle_manager.liveUpdateVehicleColors(id, vehicle, i, table_to_color(ct))
end
vehicle:setField('partConfig', '', serialize(vd.config))

kissghosts.set_pause_override(id, data.global_ghost_state == 2, true)
end

local function electrics_diff_update(data)
Expand Down Expand Up @@ -557,15 +570,10 @@ end
local function onVehicleSpawned(id)
if not network.connection.connected then return end
local vehicle = getObjectByID(id)
tempVec1:set(vehicle:getPositionXYZ())
if first_vehicle then
tempVec2:set(tempVec1.x + math.random(-5, 5), tempVec1.y + math.random(-5, 5), tempVec1.z)
vehicle:setPosition(tempVec2)
vehicle:queueLuaCommand("recovery.saveHome()")
first_vehicle = false
end
vehicle:queueLuaCommand("extensions.addModulePath('lua/vehicle/extensions/kiss_mp')")
vehicle:queueLuaCommand("extensions.loadModulesInDirectory('lua/vehicle/extensions/kiss_mp')")
vehicle:queueLuaCommand("rawset(_G, 'ghostOnReset', true)") -- this is important for ghosting

send_vehicle_config(id)
-- Attempt to workaround a bug from latest beamng update. Also prevents unicycle cloning(Somewhat)
if vehicle:getJBeamFilename() == "unicycle" then
Expand Down Expand Up @@ -628,6 +636,7 @@ local function onMissionLoaded(mission)
if not network.connection.connected then return end
M.id_map = {}
M.ownership = {}
M.id_to_owner_map = {}
M.loading_map = false
first_vehicle = true
end
Expand Down Expand Up @@ -655,6 +664,7 @@ M.attach_coupler = attach_coupler
M.detach_coupler = detach_coupler
M.attach_coupler_inner = attach_coupler_inner
M.detach_coupler_inner = detach_coupler_inner
M.send_vehicle_meta_updates = send_vehicle_meta_updates

M.set_position = set_position
M.set_position_rotation = set_position_rotation
Expand Down
14 changes: 14 additions & 0 deletions KISSMultiplayer/lua/vehicle/extensions/kiss_mp/kiss_vehicle.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ local string_buffer = require("string.buffer")
local nodes = {}
local ref_nodes = {}

M.collision = true

local last_node = 1
local nodes_per_frame = 32

Expand Down Expand Up @@ -155,11 +157,23 @@ local function send_vehicle_config()
objectId, jsonEncode(config), string_buffer.encode(data)))
end

local function set_collision(collision)
M.collision = collision

if collision then
obj:setGhostEnabled(false)
else
obj:setGhostEnabled(true)
end
end

M.update_transform_info = update_transform_info
M.apply_linear_velocity_ang_torque = apply_linear_velocity_ang_torque
M.update_eligible_nodes = update_eligible_nodes
M.apply_linear_velocity = apply_linear_velocity
M.onExtensionLoaded = onExtensionLoaded

M.set_collision = set_collision
M.send_vehicle_config = send_vehicle_config

return M
1 change: 1 addition & 0 deletions KISSMultiplayer/scripts/kiss_mp/modScript.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ print("Executing KissMP modScript...")
loadJsonMaterialsFile("art/shapes/kissmp_playermodels/main.materials.json")

setExtensionUnloadMode("kissplayers", "manual")
setExtensionUnloadMode("kissghosts", "manual")
setExtensionUnloadMode("vehiclemanager", "manual")
setExtensionUnloadMode("kisstransform", "manual")
setExtensionUnloadMode("kissui", "manual")
Expand Down
1 change: 1 addition & 0 deletions kissmp-server/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ impl Server {
vehicle.data.palete_0 = meta.colors_table[1];
vehicle.data.palete_1 = meta.colors_table[2];
vehicle.data.plate = meta.plate.clone();
vehicle.data.global_ghost_state = meta.global_ghost_state.clone();
let mut meta = meta.clone();
meta.vehicle_id = server_id;
for (_, client) in &mut self.connections {
Expand Down
Loading
Loading