void DebugGUI() { if (!Constants.DEBUG_MODE) { return; } if (GUILayout.Button ("spoon")) { if (_debugTool != DebugTools.Spoon) { _debugTool = DebugTools.Spoon; Debug.Log ("spoon On"); }else { _debugTool = DebugTools.None; Debug.Log ("spoon Off"); } } if (GUILayout.Button ("FormBomb")) { if (_debugTool != DebugTools.FormBomb) { _debugTool = DebugTools.FormBomb; Debug.Log ("FormBomb On"); }else { _debugTool = DebugTools.None; Debug.Log ("FormBomb Off"); } } }
public override void AlignPlacementMode(ScreenCoordinates mouseScreen) { const float SearchBoxSize = 1.5f; // size of search box in meters MouseCoords = ScreenToCursorGrid(mouseScreen); var mapGrid = pManager.MapManager.GetGrid(MouseCoords.GridID); if (mapGrid.IsDefaultGrid) { // check if we are on an edge of a grid // create a box around the cursor DebugTools.Assert(mapGrid.WorldPosition == Vector2.Zero); // assert that LocalPos == WorldPos var gridSearchBox = Box2.UnitCentered.Scale(SearchBoxSize).Translated(MouseCoords.Position); // find grids in search box var gridsInArea = pManager.MapManager.FindGridsIntersecting(mapGrid.ParentMapId, gridSearchBox); // find closest grid intersecting our search box. IMapGrid closest = null; var distance = float.PositiveInfinity; var intersect = new Box2(); foreach (var grid in gridsInArea) { // figure out closest intersect var gridIntersect = gridSearchBox.Intersect(grid.WorldBounds); var gridDist = (gridIntersect.Center - MouseCoords.Position).LengthSquared; if (gridDist >= distance) { continue; } distance = gridDist; closest = grid; intersect = gridIntersect; } if (closest != null) // stick to existing grid { // round to nearest cardinal dir var normal = new Angle(MouseCoords.Position - intersect.Center).GetCardinalDir().ToVec(); // round coords to center of tile var tileIndices = closest.WorldToTile(intersect.Center); var tileCenterLocal = closest.GridTileToLocal(tileIndices); var tileCenterWorld = tileCenterLocal.ToWorld(pManager.MapManager).Position; // move mouse one tile out along normal var newTilePos = tileCenterWorld + normal * closest.TileSize; MouseCoords = new GridCoordinates(closest.WorldToLocal(newTilePos), closest.Index); } //else free place } CurrentTile = mapGrid.GetTileRef(MouseCoords); float tileSize = mapGrid.TileSize; //convert from ushort to float GridDistancing = tileSize; if (pManager.CurrentPermission.IsTile) { if (!mapGrid.IsDefaultGrid) { MouseCoords = new GridCoordinates(CurrentTile.X + tileSize / 2, CurrentTile.Y + tileSize / 2, MouseCoords.GridID); } // else we don't modify coords } else { MouseCoords = new GridCoordinates(CurrentTile.X + tileSize / 2 + pManager.PlacementOffset.X, CurrentTile.Y + tileSize / 2 + pManager.PlacementOffset.Y, MouseCoords.GridID); } }
private void HandleEntityState(IComponentManager compMan, IEntity entity, EntityState?curState, EntityState?nextState) { var compStateWork = new Dictionary <uint, (ComponentState?curState, ComponentState?nextState)>(); var entityUid = entity.Uid; if (curState?.ComponentChanges != null) { foreach (var compChange in curState.ComponentChanges) { if (compChange.Deleted) { if (compMan.TryGetComponent(entityUid, compChange.NetID, out var comp)) { compMan.RemoveComponent(entityUid, comp); } } else { if (compMan.HasComponent(entityUid, compChange.NetID)) { continue; } var newComp = (Component)_compFactory.GetComponent(compChange.ComponentName !); newComp.Owner = entity; compMan.AddComponent(entity, newComp, true); } } } if (curState?.ComponentStates != null) { foreach (var compState in curState.ComponentStates) { compStateWork[compState.NetID] = (compState, null); } } if (nextState?.ComponentStates != null) { foreach (var compState in nextState.ComponentStates) { if (compStateWork.TryGetValue(compState.NetID, out var state)) { compStateWork[compState.NetID] = (state.curState, compState); } else { compStateWork[compState.NetID] = (null, compState); } } } foreach (var(netId, (cur, next)) in compStateWork) { if (compMan.TryGetComponent(entityUid, netId, out var component)) { try { component.HandleComponentState(cur, next); } catch (Exception e) { var wrapper = new ComponentStateApplyException( $"Failed to apply comp state: entity={component.Owner}, comp={component.Name}", e); #if EXCEPTION_TOLERANCE _runtimeLog.LogException(wrapper, "Component state apply"); #else throw wrapper; #endif } } else { // The component can be null here due to interp. // Because the NEXT state will have a new component, but this one doesn't yet. // That's fine though. if (cur == null) { continue; } var eUid = entityUid; var eRegisteredNetUidName = _compFactory.GetRegistration(netId).Name; DebugTools.Assert( $"Component does not exist for state: entUid={eUid}, expectedNetId={netId}, expectedName={eRegisteredNetUidName}"); } } }
public void ProcessPackets() { while (_messageChannel.Reader.TryRead(out var item)) { switch (item) { case ConnectMessage connect: { DebugTools.Assert(IsServer); async void DoConnect() { var writer = connect.ChannelWriter; var uid = _genConnectionUid(); var sessionId = new NetUserId(Guid.NewGuid()); var userName = $"integration_{uid}"; var args = await OnConnecting( new IPEndPoint(IPAddress.IPv6Loopback, 0), sessionId, userName, LoginType.Guest); if (args.IsDenied) { writer.TryWrite(new DeniedConnectMessage()); return; } writer.TryWrite(new ConfirmConnectMessage(uid, sessionId, userName)); var channel = new IntegrationNetChannel(this, connect.ChannelWriter, uid, sessionId, connect.Uid, userName); _channels.Add(uid, channel); Connected?.Invoke(this, new NetChannelArgs(channel)); } DoConnect(); break; } case DataMessage data: { IntegrationNetChannel?channel; if (IsServer) { if (!_channels.TryGetValue(data.Connection, out channel)) { continue; } } else { if (ServerChannel == null || data.Connection != ServerChannel.ConnectionUid) { continue; } channel = ServerChannel; } var message = data.Message; message.MsgChannel = channel; if (_callbacks.TryGetValue(message.GetType(), out var callback)) { callback(message); } break; } case DisconnectMessage disconnect: { if (IsServer) { if (_channels.TryGetValue(disconnect.Connection, out var channel)) { Disconnect?.Invoke(this, new NetDisconnectedArgs(channel, string.Empty)); _channels.Remove(disconnect.Connection); } } else { _channels.Clear(); } break; } case DeniedConnectMessage _: { DebugTools.Assert(IsClient); ConnectFailed?.Invoke(this, new NetConnectFailArgs("I didn't implement a deny reason!")); break; } case ConfirmConnectMessage confirm: { DebugTools.Assert(IsClient); var channel = new IntegrationNetChannel(this, NextConnectChannel !, _clientConnectingUid, confirm.UserId, confirm.AssignedUid, confirm.AssignedName); _channels.Add(channel.ConnectionUid, channel); Connected?.Invoke(this, new NetChannelArgs(channel)); break; } default: throw new ArgumentOutOfRangeException(); } } }
/// <summary> /// Recalculate line dimensions and where it has line breaks for word wrapping. /// </summary> /// <param name="font">The font being used for display.</param> /// <param name="maxSizeX">The maximum horizontal size of the container of this entry.</param> /// <param name="uiScale"></param> public void Update(Font font, float maxSizeX, float uiScale) { // This method is gonna suck due to complexity. // Bear with me here. // I am so deeply sorry for the person adding stuff to this in the future. Height = font.GetHeight(uiScale); LineBreaks.Clear(); var maxUsedWidth = 0f; // Index we put into the LineBreaks list when a line break should occur. var breakIndexCounter = 0; // If the CURRENT processing word ends up too long, this is the index to put a line break. (int index, float lineSize)? wordStartBreakIndex = null; // Word size in pixels. var wordSizePixels = 0; // The horizontal position of the text cursor. var posX = 0; var lastChar = 'A'; // If a word is larger than maxSizeX, we split it. // We need to keep track of some data to split it into two words. (int breakIndex, int wordSizePixels)? forceSplitData = null; // Go over every text tag. // We treat multiple text tags as one continuous one. // So changing color inside a single word doesn't create a word break boundary. foreach (var tag in Message.Tags) { // For now we can ignore every entry that isn't a text tag because those are only color related. // For now. if (!(tag is FormattedMessage.TagText tagText)) { continue; } var text = tagText.Text; // And go over every character. for (var i = 0; i < text.Length; i++, breakIndexCounter++) { var chr = text[i]; if (IsWordBoundary(lastChar, chr) || chr == '\n') { // Word boundary means we know where the word ends. if (posX > maxSizeX && lastChar != ' ') { DebugTools.Assert(wordStartBreakIndex.HasValue, "wordStartBreakIndex can only be null if the word begins at a new line, in which case this branch shouldn't be reached as the word would be split due to being longer than a single line."); // We ran into a word boundary and the word is too big to fit the previous line. // So we insert the line break BEFORE the last word. LineBreaks.Add(wordStartBreakIndex !.Value.index); Height += font.GetLineHeight(uiScale); maxUsedWidth = Math.Max(maxUsedWidth, wordStartBreakIndex.Value.lineSize); posX = wordSizePixels; } // Start a new word since we hit a word boundary. //wordSize = 0; wordSizePixels = 0; wordStartBreakIndex = (breakIndexCounter, posX); forceSplitData = null; // Just manually handle newlines. if (chr == '\n') { LineBreaks.Add(breakIndexCounter); Height += font.GetLineHeight(uiScale); maxUsedWidth = Math.Max(maxUsedWidth, posX); posX = 0; lastChar = chr; wordStartBreakIndex = null; continue; } } // Uh just skip unknown characters I guess. if (!font.TryGetCharMetrics(chr, uiScale, out var metrics)) { lastChar = chr; continue; } // Increase word size and such with the current character. var oldWordSizePixels = wordSizePixels; wordSizePixels += metrics.Advance; // TODO: Theoretically, does it make sense to break after the glyph's width instead of its advance? // It might result in some more tight packing but I doubt it'd be noticeable. // Also definitely even more complex to implement. posX += metrics.Advance; if (posX > maxSizeX) { if (!forceSplitData.HasValue) { forceSplitData = (breakIndexCounter, oldWordSizePixels); } // Oh hey we get to break a word that doesn't fit on a single line. if (wordSizePixels > maxSizeX) { var(breakIndex, splitWordSize) = forceSplitData.Value; if (splitWordSize == 0) { // Happens if there's literally not enough space for a single character so uh... // Yeah just don't. return; } // Reset forceSplitData so that we can split again if necessary. forceSplitData = null; LineBreaks.Add(breakIndex); Height += font.GetLineHeight(uiScale); wordSizePixels -= splitWordSize; wordStartBreakIndex = null; maxUsedWidth = Math.Max(maxUsedWidth, maxSizeX); posX = wordSizePixels; } } lastChar = chr; } } // This needs to happen because word wrapping doesn't get checked for the last word. if (posX > maxSizeX) { DebugTools.Assert(wordStartBreakIndex.HasValue, "wordStartBreakIndex can only be null if the word begins at a new line, in which case this branch shouldn't be reached as the word would be split due to being longer than a single line."); LineBreaks.Add(wordStartBreakIndex !.Value.index); Height += font.GetLineHeight(uiScale); maxUsedWidth = Math.Max(maxUsedWidth, wordStartBreakIndex.Value.lineSize); } else { maxUsedWidth = Math.Max(maxUsedWidth, posX); } Width = (int)maxUsedWidth; }
private void _onChatBoxTextSubmitted(ChatBox chatBox, string text) { DebugTools.Assert(chatBox == _currentChatBox); if (string.IsNullOrWhiteSpace(text)) { return; } // Check if message is longer than the character limit if (text.Length > _maxMessageLength) { string locWarning = Loc.GetString("Your message exceeds {0} character limit", _maxMessageLength); _currentChatBox?.AddLine(locWarning, ChatChannel.Server, Color.Orange); _currentChatBox.ClearOnEnter = false; // The text shouldn't be cleared if it hasn't been sent return; } switch (text[0]) { case ConCmdSlash: { // run locally var conInput = text.Substring(1); _console.ProcessCommand(conInput); break; } case OOCAlias: { var conInput = text.Substring(1); if (string.IsNullOrWhiteSpace(conInput)) { return; } _console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\""); break; } case AdminChatAlias: { var conInput = text.Substring(1); if (string.IsNullOrWhiteSpace(conInput)) { return; } if (_groupController.CanCommand("asay")) { _console.ProcessCommand($"asay \"{CommandParsing.Escape(conInput)}\""); } else { _console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\""); } break; } case MeAlias: { var conInput = text.Substring(1); if (string.IsNullOrWhiteSpace(conInput)) { return; } _console.ProcessCommand($"me \"{CommandParsing.Escape(conInput)}\""); break; } default: { var conInput = _currentChatBox.DefaultChatFormat != null ? string.Format(_currentChatBox.DefaultChatFormat, CommandParsing.Escape(text)) : text; _console.ProcessCommand(conInput); break; } } }
public VVPropEditor SetProperty(ViewVariablesBlobMembers.MemberData member) { NameLabel.Text = member.Name; var type = Type.GetType(member.Type); _bottomLabel.Text = $"Type: {member.TypePretty}"; VVPropEditor editor; if (type == null || !_robustSerializer.CanSerialize(type)) { // Type is server-side only. // Info whether it's reference or value type can be figured out from the sent value. if (type?.IsValueType == true || member.Value is ViewVariablesBlobMembers.ServerValueTypeToken) { // Value type, just display it stringified read-only. editor = new VVPropEditorDummy(); } else { // Has to be a reference type at this point. DebugTools.Assert(member.Value is ViewVariablesBlobMembers.ReferenceToken || member.Value == null || type?.IsClass == true || type?.IsInterface == true); editor = _viewVariablesManager.PropertyFor(type ?? typeof(object)); } } else { editor = _viewVariablesManager.PropertyFor(type); } var view = editor.Initialize(member.Value, !member.Editable); if (!view.HorizontalExpand) { NameLabel.HorizontalExpand = true; } NameLabel.MinSize = new Vector2(150, 0); TopContainer.AddChild(view); /* * _beingEdited = obj; * _editedProperty = propertyInfo; * DebugTools.Assert(propertyInfo.DeclaringType != null); * DebugTools.Assert(propertyInfo.DeclaringType.IsInstanceOfType(obj)); * * DebugTools.Assert(ViewVariablesUtility.TryGetViewVariablesAccess(fieldInfo, out var access)); * NameLabel.Text = propertyInfo.Name; * * _bottomLabel.Text = $"Type: {propertyInfo.PropertyType.FullName}"; * * var editor = vvm.PropertyFor(propertyInfo.PropertyType); * var value = propertyInfo.GetValue(obj); * * var view = editor.Initialize(value, access != VVAccess.ReadWrite); * if (view.SizeFlagsHorizontal != SizeFlags.FillExpand) * { * NameLabel.HorizontalExpand = true; * } * NameLabel.MinSize = new Vector2(150, 0); * TopContainer.AddChild(view); * editor.OnValueChanged += v => { propertyInfo.SetValue(obj, v); }; */ return(editor); }
/// <summary> /// Have a certain chance to return a boolean. /// </summary> /// <param name="random">The random instance to run on.</param> /// <param name="chance">The chance to pass, from 0 to 1.</param> public static bool Prob(this IRobustRandom random, float chance) { DebugTools.Assert(chance <= 1 && chance >= 0, "Chance must be in the range 0-1"); return(random.NextDouble() <= chance); }
private void OnConnectFailed(object?sender, NetConnectFailArgs args) { DebugTools.Assert(RunLevel == ClientRunLevel.Connecting); Reset(); }
private async Task _moveToPage(int page) { // TODO: Network overhead optimization potential: // Right now, (in NETWORK mode) if I request page 5, it has to cache all 5 pages, // now the server obviously (enumerator and all that) has to TOO, but whatever. // The waste is that all pages are also SENT, even though we only really care about the fifth at the moment. // Because the cache can't have holes (and also the network system is too simplistic at the moment, // if you do do a by-page pull and you're way too far along, // you'll just get 0 elements which doesn't tell you where it ended but that's kinda necessary. if (page < 0) { page = 0; } if (page > HighestKnownPage || (!_ended && page == HighestKnownPage)) { if (_ended) { // The requested page is higher than the highest page we have (and we know this because the enumerator ended). page = HighestKnownPage; } else { // The page is higher than the highest page we have, but the enumerator hasn't ended yet so that might be valid. // Gotta get more data. await _cacheTo((page + 1) *ElementsPerPage); if (page > HighestKnownPage) { // We tried, but the enumerator ended before we reached our goal. // Oh well. DebugTools.Assert(_ended); page = HighestKnownPage; } } } _elementsVBox.DisposeAllChildren(); for (var i = page * ElementsPerPage; i < ElementsPerPage * (page + 1) && i < _cache.Count; i++) { var element = _cache[i]; ViewVariablesPropertyEditor editor; if (element == null) { editor = new ViewVariablesPropertyEditorDummy(); } else { var type = element.GetType(); editor = Instance.ViewVariablesManager.PropertyFor(type); } var control = editor.Initialize(element, true); if (editor is ViewVariablesPropertyEditorReference refEditor) { if (_networked) { var iSafe = i; refEditor.OnPressed += () => Instance.ViewVariablesManager.OpenVV( new ViewVariablesSessionRelativeSelector(Instance.Session.SessionId, new object[] { new ViewVariablesEnumerableIndexSelector(iSafe), })); } else { refEditor.OnPressed += () => Instance.ViewVariablesManager.OpenVV(element); } } _elementsVBox.AddChild(control); } _page = page; _updateControls(); }