const std = @import("std"); const basis = @import("basis"); const game_messages = @import("../game_messages.zig"); const game_input = @import("../game_input.zig"); const ComponentInterface = basis.components.ComponentInterface; const ZigCraneControlSystemComponent = @import("ZigCraneControlSystemComponent.zig").ZigCraneControlSystemComponent; const Vec3 = basis.math.Vec3; const Message = basis.messaging.Message; const MessageParameters = basis.messaging.MessageParameters; const AvatarTrackingComponent = basis.component_contexts.AvatarTrackingComponent; pub const ZigCraneAvatarComponent = struct { const Self = @This(); interface: ComponentInterface, context: AvatarTrackingComponent, aimingEnabled: bool = false, aimTargetPosition: basis.math.Vec3 = basis.math.Vec3.Zero, cleanUpInputContext: bool = false, craneControlSystemComponent: ?*ZigCraneControlSystemComponent = null, isServerAvatar: bool = false, //---------------------------------------------------- // init: //---------------------------------------------------- pub fn init(interface: ComponentInterface, context: AvatarTrackingComponent) Self { return Self{ .interface = interface, .context = context, }; } //---------------------------------------------------- // Public functions: //---------------------------------------------------- pub fn create(self: *Self) void { self.context.subscribeToMessageCategory(game_messages.MESSAGE_CATEGORY_SLIDE_PLAYER_CONTROL); self.context.subscribeToMessageCategory(game_messages.MESSAGE_CATEGORY_SLIDE_GAME_LOGIC); } pub fn destroy(self: *Self) void { self.cleanUpInput(); } pub fn onParentCreated(self: *Self) void { self.craneControlSystemComponent = self.context.parent.getComponent(ZigCraneControlSystemComponent, "craneControlSystemComponent"); } pub fn preTick(self: *Self, tickDeltaTime: f32) void { if (self.isServerAvatar) { self.tickCraneInput(); } } pub fn tick(self: *Self, tickDeltaTime: f32) void { if (self.context.isClientLocalAvatar()) { var p = self.context.allocMsgParams(); p.addVec3(self.context.transform.getPosition()); p.addQuaternion(self.context.transform.getOrientation()); p.addVec3(self.context.transform.getLinearVelocity()); p.addVec3(self.context.transform.getAngularVelocity()); self.context.sendMessage(basis.engine_messages.MESSAGE_LOCAL_AVATAR_TRANSFORM_UPDATED, p); } } pub fn onMessageReceived(self: *Self, message: Message, senderNameHash: basis.string.StringHash, parameters: *MessageParameters) void { switch (message) { game_messages.MESSAGE_AIMING_UPDATED => { const hostID = parameters.getInt(); const aimingEnabled = (parameters.getInt() == 1); const aimTargetPosition = parameters.getVec3(); const aimDirection = parameters.getVec3(); if (hostID == self.context.getAvatarHostID()) { self.aimingEnabled = aimingEnabled; self.aimTargetPosition = aimTargetPosition; if (self.craneControlSystemComponent) |ccs| { if (self.aimingEnabled) { ccs.updateAiming(aimTargetPosition, aimDirection); } else { ccs.returnToRestPose(); } } } }, else => {}, } } pub fn onBecameClientLocalAvatar(self: *Self) void { var p = self.context.allocMsgParams(); self.context.sendMessage(game_messages.MESSAGE_SET_CAMERA_MODE_VEHICLE, p); self.sendCameraParameters(); self.initVehicleHUD(); if (!basis.input.InputManager.isGameInputContextEnabled(game_input.InputContextCraneControls)) { basis.input.InputManager.addGameInputContextToFront(game_input.InputContextCraneControls); self.cleanUpInputContext = true; } } pub fn onLostClientLocalAvatar(self: *Self) void { self.cleanUpInput(); } pub fn onBecameServerAvatar(self: *Self, hostID: i32) void { self.isServerAvatar = true; } pub fn onLostServerAvatar(self: *Self, hostID: i32) void { self.isServerAvatar = false; } //---------------------------------------------------- // Private functions: //---------------------------------------------------- fn sendCameraParameters(self: *Self) void { var p = self.context.allocMsgParams(); p.addVec3(Vec3.init(0.0, 5.0, -12.0)); // drivingCameraInitPosition p.addVec3(Vec3.init(0.0, 1.3, 0.0)); // drivingCameraLookAtPosition p.addFloat(15.0); // orbitCameraDistance p.addVec3(Vec3.init(0.0, 6.0, 0.0)); // orbitCameraLookAtPosition p.addFloat(4.5); // orbitCameraSidewaysOffset p.addVec3(Vec3.init(0.0, 5.0, -12.0)); // drivingCameraInitPositionHauling p.addVec3(Vec3.init(0.0, 1.3, 0.0)); // drivingCameraLookAtPositionHauling p.addFloat(15.0); // orbitCameraDistanceHauling p.addVec3(Vec3.init(0.0, 6.0, 0.0)); // orbitCameraLookAtPositionHauling p.addFloat(4.5); // orbitCameraSidewaysOffsetHauling self.context.sendMessage(game_messages.MESSAGE_SET_VEHICLE_CAMERA_PARAMETERS, p); } fn initVehicleHUD(self: *Self) void { const hasWeapons = false; var p = self.context.allocMsgParams(); p.addInt(@boolToInt(hasWeapons)); self.context.sendMessage(game_messages.MESSAGE_INIT_VEHICLE_HUD, p); } fn cleanUpInput(self: *Self) void { if (self.cleanUpInputContext) { basis.input.InputManager.removeGameInputContext(game_input.InputContextCraneControls); self.cleanUpInputContext = false; } } fn tickCraneInput(self: *Self) void { if (self.craneControlSystemComponent) |ccs| { const upDown = self.context.getInputRange(game_input.InputIDCraneMoveVertically); const forwardBackward = self.context.getInputRange(game_input.InputIDCraneMoveHorizontally); ccs.moveArm(upDown, forwardBackward); if (self.context.getInputAction(game_input.InputIDCraneToggleAttractor)) { ccs.toggleAttractor(); } } } };