Hazel游戏引擎(008-009)事件系统

news2024/11/17 3:29:17

文中若有代码、术语等错误,欢迎指正

文章目录

  • 008、事件系统-设计
  • 009、事件系统-自定义事件
    • 前言
    • 自定义事件类与使用
      • 声明与定义类代码
      • 包含头文件
      • 使用事件
    • 事件调度器代码
  • C++知识:Function
    • Bind用法
    • function基本使用
  • 012、事件系统-Demo
    • Layer用EventDispacher拦截处理事件(56)(难理解)
    • Application设置window回调函数与回调(123)
    • Application将事件传给Layer(4)与整个事件系统流程

008、事件系统-设计

  • 此节目的

    理清顺序和设计才能更好的编码

  • 设计如图

    • 声明

      图是我自己缝合的,流程与大意没错,但是不符合软件工程对应图的规范。

      大致是根据视频草稿图与大意画的

    • 使用时序图简单表示

      请添加图片描述

    • 使用类图详细表示

      在软件工程中,类图没有消息传递的,不符合规范,但大意是这样

      请添加图片描述

009、事件系统-自定义事件

前言

  • 此节目的

    由008节的计划窗口事件图中的2.3将glfw窗口事件分组成自己系统的事件Event,即写出对应glfw窗口事件的自定义事件Event类

  • 事件最终的设计

    为了简便,自定义事件是立即处理事件,没有缓冲事件。

    缓冲事件:键盘a一直按下第一个立刻输出,顿了一下才一直输出。

  • glfw窗口事件

    • 窗口相关事件

      重新调整大小、窗口关闭等

    • 鼠标事件

      移动、滚动、按下

    • 键盘事件

      键盘按下、释放

  • 类图

    请添加图片描述

自定义事件类与使用

声明与定义类代码

  • 声明

    由于类过多,只写几个类

  • Event

    /*
    	为了简便,自定义事件是立即处理事件,没有缓冲事件。
    	缓冲事件:键盘a一直按下第一个立刻输出,顿了一下才一直输出。
    */
    // 事件类别-一个类一个标识
    enum class EventType{
        None = 0,
        WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved,
        AppTick, AppUpdate, AppRender,
        KeyPressed, KeyReleased,
        MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled
    };
    // 事件分类-多个类一个分类,即多个类属于同一个分类
    enum EventCategory
    {
        None = 0,
        EventCategoryApplication	= BIT(0),	// 1
        EventCategoryInput			= BIT(1),	// 2
        EventCategoryKeyboard		= BIT(2),	// 4
        EventCategoryMouse			= BIT(3),	// 8
        EventCategoryMouseButton	= BIT(4)	// 16
    };
    // 宏定义:每个子类都需要重写父类虚函数代码,可以用宏定义简洁代码
    #define EVENT_CLASS_TYPE(type) static EventType GetStaticType() { return EventType::##type; }\
    								virtual EventType GetEventType() const override { return GetStaticType(); }\
    								virtual const char* GetName() const override { return #type; }
    
    #define EVENT_CLASS_CATEGORY(category) virtual int GetCategoryFlags() const override { return category; }
    
    class HAZEL_API Event
    {
        friend class EventDispatcher;
        public:
        virtual EventType GetEventType() const = 0;		// 获取本事件是哪个类型
        virtual const char* GetName() const = 0;		// 获取本事件的名称c字符数组
        virtual int GetCategoryFlags() const = 0;		// 获取本事件属于哪个分类
        virtual std::string ToString() const { return GetName(); }	// 获取本事件的名称从c字符数组转为字符串
    
        inline bool IsInCategory(EventCategory category)
        {
            return GetCategoryFlags() & category;
        }
        protected:
        bool m_Handled = false;
    };
    
  • WindowResizeEvent

    class HAZEL_API WindowResizeEvent : public Event
    {
        public:
        WindowResizeEvent(unsigned int width, unsigned int height)
            : m_Width(width), m_Height(height) {}
    
        inline unsigned int GetWidth() const { return m_Width; }
        inline unsigned int GetHeight() const { return m_Height; }
    
        std::string ToString() const override
        {
            std::stringstream ss;
            ss << "WindowResizeEvent: " << m_Width << ", " << m_Height;
            return ss.str();
        }
    	// 关键地方:用宏定义来重写虚函数
        EVENT_CLASS_TYPE(WindowResize)
            EVENT_CLASS_CATEGORY(EventCategoryApplication)
            private:
        unsigned int m_Width, m_Height;
    };
    
  • 关键地方:用宏定义来重写虚函数

    // 宏定义:每个子类都需要重写父类虚函数代码,可以用宏定义简洁代码
    #define EVENT_CLASS_TYPE(type) static EventType GetStaticType() { return EventType::##type; }\
    								virtual EventType GetEventType() const override { return GetStaticType(); }\
    								virtual const char* GetName() const override { return #type; }
    
    EVENT_CLASS_TYPE(WindowResize)
    EVENT_CLASS_CATEGORY(EventCategoryApplication)
    // 会编译成
    static EventType GetStaticType() { return EventType::WindowResize; } virtual EventType GetEventType() const override { return GetStaticType(); } virtual const char* GetName() const override { return "WindowResize"; }
    virtual int GetCategoryFlags() const override { return EventCategoryApplication; }
    

    可见,##type,是保持为变量,#type是转换为字符串

包含头文件

  • premake的lua脚本中

    includedirs
    {
        "%{prj.name}/src",
        "%{prj.name}/vendor/spdlog/include"
    }
    

    所以Hazel项目的包含目录包含src目录

    // 因为Event.h所在src/Hazel/Events/Event.h
    // 其它类包含Event.h,可以写成
    #include "Hazel/Events/Event.h"// 而不用前缀src
    

    重新编译

使用事件

  • application.h

    #include "Core.h"
    #include "Events/Event.h"// 包含事件基类
    
    namespace Hazel {
    
  • Application.cpp

    #include "Application.h"
    #include "Hazel/Events/ApplicationEvent.h" // 包含具体事件
    #include "Hazel/Log.h"
    
    namespace Hazel {
    	Application::Application(){}
    	Application::~Application(){}
    	void Application::Run()
    	{
    		WindowResizeEvent e(1280, 720);	// 使用自定义事件
    		if (e.IsInCategory(EventCategoryApplication))	// 判断是否对应的分类
    		{
    			HZ_TRACE(e);	// 输出事件
    		}
    		if (e.IsInCategory(EventCategoryInput))
    		{
    			HZ_TRACE(e);
    		}
    		while (true);
    	}
    }
    
  • 效果

    请添加图片描述

事件调度器代码

// 事件调度器类
class EventDispatcher
{
    template<typename T>
    using EventFn = std::function<bool(T&)>;	// 声明function,接受返回类型bool,参数是T&的函数
    public:
    EventDispatcher(Event& event)
        : m_Event(event)
        {
        }
    template<typename T>
    bool Dispatch(EventFn<T> func)				// function参数接收函数指针
    {
        if (m_Event.GetEventType() == T::GetStaticType())	// 拦截的事件和想处理的事件类型是否匹配
        {
            m_Event.m_Handled = func(*(T*)&m_Event);		// 处理拦截的事件
            return true;
        }
        return false;
    }
    private:
    Event& m_Event;								// 拦截的事件
};

这个类的本身与作用由于(function+模板)变得很难看懂,可以看结合开头的事件设计图和后面的function基本使用代码一步一步理解

C++知识:Function

Bind用法

#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;// 占位符空间
void f(int a, int b, int c, int d, int e)
{
	cout << a << " " << b << " " << c << " " << d << " " << e << endl;
}
// _1 是在命名空间里的,bind可以翻转参数位置
int main(){
	int a = 1, b = 2, c = 3;
	auto g = bind(f, a, b, c, _2, _1);
	g(4, 5);	// 1 2 3 5 4
	return 0;
}
  • 说明
    • bind可以用_1,_2预占位,g可以理解是function<void(int a, int b, int c, int d, int e);function对象
    • auto g = bind(f, a, b, c, _2, _1);将f函数绑定到function对象g上,并定好第一、二、三个参数
    • g(4, 5),将调用执行f函数,4将绑定到_1上,5将绑定到_2上,本来_1实参会赋给f函数的d形参,_2实参给e形参,但由于bind时改变了对应位置
    • 于是_1给e,_2给d,输出 1 2 3 5 4

function基本使用

#include <iostream>
#include <string>
#include <functional>
using namespace std;
using namespace std::placeholders;// 占位符空间

// 事件类与函数定义
class Event {							// 事件基类
public:
	virtual void Say() { cout << "Event::Say()" << endl; }
	bool m_Handled;						// 事件是否处理完
};
class WindowCloseEvent : public Event {	// 窗口关闭事件子类
public:
	virtual void Say() { cout << "WindowEvent::Say()" << endl;}
};
void LayerOnEvent(Event& e) {
	e.Say();
	cout << "LayerOnEvent(Event& e)" << endl;
}

// 4.using+带泛型的function
template<typename T>
using TemplateEventFn = std::function<void(T&)>;

// 5.额外理解,宏定义
#define BIND_EVENT_FN(x) bind(&x, _1)

int main() {
	// 1.普通的function
	Event e1;
	function<void(Event&)> func1 = LayerOnEvent;// 绑定返回类型void,参数是Event的函数
	func1(e1);

	// 2.使用using 代替function
	using EventFn = std::function<void(Event&)>;
	EventFn func2 = LayerOnEvent;
	func2(e1);
	
	// 3.使用bind
	function<void(Event&)> func3_1 = bind(&LayerOnEvent, _1);
	func3_1(e1);

	EventFn func3_2 = bind(&LayerOnEvent, _1);// bind第一个参数函数地址,第二个参数是调用Print函数时的参数
	func3_2(e1);

	// 4.使用template的 function
	TemplateEventFn<Event> func4 = LayerOnEvent;
	func4(e1);

	func4 = bind(&LayerOnEvent, _1);
	func4(e1);

	// 5.额外理解,宏定义
	TemplateEventFn<Event> func5 = BIND_EVENT_FN(LayerOnEvent);
	func5(e1);

	// 6.额外理解。尝试引用类型是否能执行子类的虚函数
	function<void(Event&)> func6 = LayerOnEvent;
	WindowCloseEvent windowe1;
	Event& event1 = windowe1;
	func6(event1);	
	/*
		WindowEvent::Say()
		LayerOnEvent(Event& e)
	*/
	return 0;
}

012、事件系统-Demo

  • 声明

    由于008节设计了事件系统,而009只是实现了自定义事件,占整个事件系统的很小部分

    于是我把012窗口事件的内容简化成demo,符合一开始的计划事件图。

    demo是分为一个小点一个小点的,更好来理解整个事件系统。

Layer用EventDispacher拦截处理事件(56)(难理解)

  • 前言

    此点Demo代码是对应一开始计划事件系统类图的第5、6步,而其它步骤的代码是模拟并且略过

    请添加图片描述

  • 代码

    阅读代码,请按照注释的1、2、3、4、5、5.1…顺序阅读

    #include <iostream>
    #include <string>
    #include <functional>
    using namespace std;
    using namespace std::placeholders;// 占位符空间
    
    // 事件类定义//
    class Event {							// 事件基类
    public:
    	virtual void Say() { cout << "Event::Say()" << endl; }
    	bool m_Handled;						// 事件是否处理完
    };
    class WindowCloseEvent : public Event {	// 窗口关闭事件子类
    public:
    	virtual void Say() { cout << "WindowEvent::Say()" << endl; }
    };
    
    // 事件调度器//
    class EventDispatcher {
    public:
    	EventDispatcher(Event& event) :m_Event(event) {}
    	
    	template<typename T>
    	using TemplateEventFn = std::function<bool(T&)>;	// 使用using+模板function
    
    	// 5.2 using TemplateEventFn = function<void(WindowCloseEvent&)> 与 TemplateEventFn<WindowCloseEvent> func
    	template<typename T>
    	void Dispatch(TemplateEventFn<T> func) {			// 此时func = Layer::OnWindowClose
    		// 5.3 拦截的事件m_Event与layer层想处理的事件类型是否匹配
    		if (true) {										// 假设匹配
    			cout << "EventDispatcher::Dispatch(TemplateEventFn<T> func)" << endl;
    			// 6 执行layer的OnWindowClose处理拦截的m_Event事件
    			m_Event.m_Handled = func(*(T*)&m_Event);
    			/*	
    				(0)	函数声明:OnWindowClose(WindowEvent& e);
    				(0) 显式调用:OnWindowClose(*(WindowEvent*)&m_Event)	
    				(1) OnWindowClose参数要求WindowEvent,而m_Event是Event类型,所以要(WindowEvent*)&m_Event
    				(2) OnWindowClose参数是引用类型,所以要*(WindowEvent*)&m_Event
    			*/
    		}
    	}
    private:
    	Event& m_Event;										// 拦截的事件
    };
    // Layer层//
    class Layer {											// 属于Application的layer层
    public:
    	// 5.每个Layer层的OnEvent,用事件调度器,拦截自己层想要拦截的事件并且处理
    	void OnEvent(Event& e) {
    		EventDispatcher dispatcher(e);
    		// 5.1拦截WindowCloseEvent事件,并用本类的OnWindowClose函数处理
    		dispatcher.Dispatch<WindowCloseEvent>(bind(&Layer::OnWindowClose, this, _1));// bind在上一小点有demo,this在类时要使用,_1依旧是执行OnWindowClose的参数
    	}
    	bool OnWindowClose(WindowCloseEvent& e) {
    		e.Say();
    		cout << "Layer::OnWindowClose(WindowCloseEvent& e)" << endl;
    		return true;									// 代表处理完了
    	}
    };
    
    int main() {
    	// 1.Application对象创建窗口类,窗口类初始化了glfw窗口
    	// 2.将glfw窗口事件封装成自己系统的事件
    	WindowCloseEvent windowe1;				
    	// 3.回调Application的OnEvent函数,并将事件作为其OnEvent的参数
    	// 4.Application的OnEvent,将事件传递给Application的所有Layer层的OnEvent
    	Layer layer;
    	layer.OnEvent(windowe1);
    	return 0;
    }
    
  • 效果

Application设置window回调函数与回调(123)

  • 前言

    此点是对应一开始计划事件系统类图的第1、2、3步,但没有glfw窗口,只能模拟glfw窗口事件

  • 代码

    #include <iostream>
    #include <string>
    #include <functional>
    using namespace std;
    using namespace std::placeholders;// 占位符空间
    
    // 事件类定义//
    class Event {							// 事件基类
    public:
    	virtual void Say() { cout << "Event::Say()" << endl; }
    	bool m_Handled;						// 事件是否处理完
    };
    class WindowCloseEvent : public Event {	// 窗口关闭事件子类
    public:
    	virtual void Say() { cout << "WindowEvent::Say()" << endl;}
    };
    
    // 窗口类定义//
    class Window {
    public:
    	using EventCallbackFn = std::function<void(Event&)>;	// 声明function类型void function(Event&)
    	static Window* CreateWindow() {							// 模拟创建窗口
    		return new Window;
    	}
    	void SetEventCallback(const EventCallbackFn& callback) {
    		EventCallback = callback;							// 绑定Application::OnEvent
    	}
    	void SendEvent() {
    		cout << "Window::模拟glfw窗口事件" << endl;
    		// 2.将glfw窗口事件封装成自己系统的事件
    		WindowCloseEvent windowe;
    		// 3.回调Application的OnEvent函数,并将事件作为其OnEvent的参数
    		EventCallback(windowe);
    	}
    	EventCallbackFn EventCallback;							// 定义function
    };
    
    // 应用层类定义//
    class Application {
    public:
    	Window* win;											// 持有的窗口类
    	void OnEvent(Event& event) {
    		event.Say();
    		cout << "Application::OnEvent(Event& event)" << endl;
    		// 4.Application的OnEvent,将事件传递给Application的所有Layer层的OnEvent
    		// ......
    	}
    };
    int main() {
    	Application app;
    	// 1.1Application对象创建窗口类,窗口类初始化了glfw窗口
    	app.win = Window::CreateWindow();
    	// 1.2Application设置窗口事件的回调函数
    	app.win->SetEventCallback(bind(&Application::OnEvent, app, _1));// bind的argument1是函数地址,arug2是哪个类,arug3是调用OnEvent的参数
    	// 1.3模拟glfw窗口事件
    	app.win->SendEvent();
    	return 0;
    }
    
  • 效果

Application将事件传给Layer(4)与整个事件系统流程

  • 前言

    此点是对应一开始计划事件系统类图的第4步,并且整合前两点的代码,除了缺少glfw窗口与glfw窗口事件是完整的事件系统流程

  • 代码

    #include <iostream>
    #include <string>
    #include <functional>
    using namespace std;
    using namespace std::placeholders;// 占位符空间
    
    // 事件类定义//
    class Event {							// 事件基类
    public:
    	virtual void Say() { cout << "Event::Say()" << endl; }
    	bool m_Handled;						// 事件是否处理完
    };
    class WindowCloseEvent : public Event {	// 窗口事件子类
    public:
    	virtual void Say() { cout << "WindowEvent::Say()" << endl;}
    };
    // 事件调度器//
    class EventDispatcher {
    public:
    	EventDispatcher(Event& event) :m_Event(event) {}
    
    	template<typename T>
    	using TemplateEventFn = std::function<bool(T&)>;	// 使用using+模板function
    
    	// 5.2 using TemplateEventFn = function<void(WindowCloseEvent&)> 与 TemplateEventFn<WindowCloseEvent> func
    	template<typename T>
    	void Dispatch(TemplateEventFn<T> func) {			// 此时func = Layer::OnWindowClose
    		// 5.3 拦截的事件m_Event与layer层想处理的事件类型是否匹配
    		if (true) {										// 假设匹配
    			cout << "EventDispatcher::Dispatch(TemplateEventFn<T> func)" << endl;
    			// 6 执行layer的OnWindowClose处理拦截的m_Event事件
    			m_Event.m_Handled = func(*(T*)&m_Event);
    			/*
    				(0)	函数声明:OnWindowClose(WindowEvent& e);
    				(0) 显式调用:OnWindowClose(*(WindowEvent*)&m_Event)
    				(1) OnWindowClose参数要求WindowEvent,而m_Event是Event类型,所以要(WindowEvent*)&m_Event
    				(2) OnWindowClose参数是引用类型,所以要*(WindowEvent*)&m_Event
    			*/
    		}
    	}
    private:
    	Event& m_Event;										// 拦截的事件
    };
    // Layer层//
    class Layer {											// 属于Application的layer层
    public:
    	// 5.每个Layer层的OnEvent,用事件调度器,拦截自己层想要拦截的事件并且处理
    	void OnEvent(Event& e) {
    		EventDispatcher dispatcher(e);
    		// 5.1拦截WindowCloseEvent事件,并用本类的OnWindowClose函数处理
    		dispatcher.Dispatch<WindowCloseEvent>(bind(&Layer::OnWindowClose, this, _1));// bind在上一小点有demo,this在类时要使用,_1依旧是执行OnWindowClose的参数
    	}
    	bool OnWindowClose(WindowCloseEvent& e) {
    		e.Say();
    		cout << "Layer::OnWindowClose(WindowCloseEvent& e)" << endl;
    		return true;									// 代表处理完了
    	}
    };
    // 窗口类定义//
    class Window {
    public:
    	using EventCallbackFn = std::function<void(Event&)>;	// 声明function类型void function(Event&)
    	static Window* CreateWindow() {							// 模拟创建窗口
    		return new Window;
    	}
    	void SetEventCallback(const EventCallbackFn& callback) {
    		EventCallback = callback;							// 绑定Application::OnEvent
    	}
    	void SendEvent() {
    		cout << "Window::模拟glfw窗口事件" << endl;
    		// 2.将glfw窗口事件封装成自己系统的事件
    		WindowCloseEvent windowe;
    		// 3.回调Application的OnEvent函数,并将事件作为其OnEvent的参数
    		EventCallback(windowe);
    	}
    	EventCallbackFn EventCallback;							// 定义function
    };
    
    // 应用层类定义//
    class Application {
    public:
    	Window* win;											// 持有的窗口类
    	void OnEvent(Event& event) {
    		cout << "Application::OnEvent(Event& event)" << endl;
    		// 4.Application的OnEvent,将事件传递给Application的所有Layer层的OnEvent
    		Layer layer;
    		layer.OnEvent(event);
    	}
    };
    int main() {
    	Application app;
    	// 1.1Application对象创建窗口类,窗口类初始化了glfw窗口
    	app.win = Window::CreateWindow();
    	// 1.2Application设置窗口事件的回调函数
    	app.win->SetEventCallback(bind(&Application::OnEvent, app, _1));// bind的argument1是函数地址,arug2是哪个类,arug3是调用OnEvent的参数
    	// 1.3模拟glfw窗口事件
    	app.win->SendEvent();
    	return 0;
    }
    
  • 效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/634598.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7-3 sdut-oop-6 计算各种图形的周长(多态)

定义接口或类 Shape&#xff0c;定义求周长的方法length()。 定义如下类&#xff0c;实现接口Shape或父类Shape的方法。 &#xff08;1&#xff09;三角形类Triangle &#xff08;2&#xff09;长方形类Rectangle &#xff08;3&#xff09;圆形类Circle等。 定义测试类Shap…

QT基础教程之一创建Qt项目

QT基础教程1创建Qt项目 根据模板创建 打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项 弹出New Project对话框&#xff0c;选择Qt Widgets Application 选择【Choose】按钮&#xff0c;弹出如下对话框 设置项目名称和路径&#xff0c;…

Cesium雷达追踪追踪(雷达探照效果)

Cesium雷达追踪追踪(圆锥体效果) 文章最后附有源码!!!!!!!!!!!!!!!!! 解析 第一步 、从gif图中可以看出,首先添加了两个运动的实体(在cesium entity与时间轴关联(添加运动轨迹))中有讲解 第二步、添加一个圆锥,修改圆锥朝向,来表示跟综照射效果,…

Windows安装MySQL及Python操作MySQL数据库脚本实例详解

1、Windows 上安装 MySQL 便于测试&#xff0c;笔者在 windows 上安装 MySQL&#xff0c;如有现成Linux下的MySQL和Python环境&#xff0c;也可直接使用。MySQL的官网下载链接安装步骤1)下载后的mysql-5.7.23-winx64.zip安装包解压至某一位置&#xff0c;在mysql-5.7.23-winx6…

Linux学习之用户管理useradd、userdel、passwd、usermod和chage

useradd 超级管理员root才能使用useradd 用户名添加用户&#xff0c;这条命令会新增一个用户&#xff0c;然后为新增用户在/home下新添一个用户名称相同的目录&#xff0c;在/var/spool/mail目录下添加一个用户名称相同的文件&#xff0c;而且还会在/etc/passwd、/etc/shadow和…

【Unity入门】25.入门结课Demo--神鸟大战怪兽

【Unity入门】入门结课Demo--神鸟大战怪兽 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 (一) 前言 经过了两个月的学习&#xff0c;我们也顺利的完成了入门课程&#xff0c;最后就用一个Demo作为我们的结课句号吧&am…

【夜深人静学数据结构与算法 | 第一篇】KMP算法

目录 前言&#xff1a; KMP算法简介&#xff1a; 引入概念&#xff1a; 前缀后缀 前缀表&#xff1a; 简单例子&#xff1a; 暴力遍历&#xff1a; KMP算法&#xff1a;​ KMP算法难点&#xff1a; 总结&#xff1a; 前言&#xff1a; 本篇我们将详细的从理论层面介绍一…

理解和创建Windows和Linux下的动态和静态库区别

一、引言 在计算机编程的世界中&#xff0c;库是一个非常重要的改变。它的出现提供了一种共享和重用代码的可能性&#xff0c;复杂的程序因为动态库的出现而变得简洁和方便。然而&#xff0c;库并不是单一的&#xff1a;它们可以是动态的&#xff0c;也可以是静态的&#xff0…

达梦数据库的下载与安装(Linux)

一、创建用户组 1、创建一个用户组和用户 添加分组 groupadd dinstall添加用户 useradd -g dinstall dmdba设置用户名和密码 echo "dameng123" | passwd --stdin dmdba查看操作系统中id为 dmdba 的用户的用户ID&#xff08;uid&#xff09;、组ID&#xff08;gi…

web漏洞-逻辑越权之水平垂直越权全解(33)

他是业务逻辑层面&#xff0c;和一些业务方便应用的安全问题&#xff0c;这个是因为代码层面没用考虑到的逻辑关系所造成的安全问题&#xff0c;越权是其中一个比较关键的问题。登录是指在登录这里出现了安全问题&#xff0c;业务等等今天只说越权。 越权漏洞 分为水平和垂直…

容器镜像按层分析工具dive

概述 dive是一个容器镜像分析工具&#xff0c;可以直观的看到容器每一层变动了哪些文件&#xff0c;每一层占用的磁盘空间&#xff0c;这样也就可以看到镜像的历史构建过程&#xff1b;同时也可以看到镜像的磁盘空间使用率&#xff0c;面对特别大的镜像文件是&#xff0c;可以…

【论文随笔】Rewrite-Based Decomposition of Signal Temporal Logic Specifications

文章目录 Overview1 IntroLTL任务分解STL任务分解本文工作 Background and Problem DefinitionSTLAgent假设与问题方法 An STL Rewriting SystemRewriting SystemFormula Rewrite DAG Decomposing STL智能体编队任务分解最优分解 Exploring the Formula Rewrite DAG心得体会 多…

如何创建可引导的 macOS 安装介质

如何创建可引导的 macOS 安装介质 如何创建可引导的 macOS 安装器 | 如何制作 macOS USB 启动盘 请访问原文链接&#xff1a;https://sysin.org/blog/macos-createinstallmedia/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.or…

asp.net卷烟物价管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net卷烟物价管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言开发 asp.net卷烟物价管理系统VS开发sq…

清华青年AI自强作业hw3_2:前向传播和反向传播实战

清华青年AI自强作业hw3_2&#xff1a;前向传播和反向传播实战 实现过程各层参数维度分析拟合结果相关链接 一起学AI系列博客&#xff1a;目录索引 前向传播和反向传播的公式理解化用于作业hw3_2中&#xff1a;&#xff1a;用NN网络拟合小姐姐喜好分类 完成前向传播、反向传播算…

【JavaEE进阶之Spring】一分钟让你学会什么是Spring以及如何使用创建Spring

前言&#xff1a; &#x1f49e;&#x1f49e;今天我们正式进入到JavaEE进阶的学习中了&#xff0c;在JavaEE进阶的学习中&#xff0c;我们最主要的就是学习Spring框架。 &#x1f49f;&#x1f49f;那我们从今天就要逐渐从最基础的Spring开始&#xff0c;教会大家什么是Spring…

54、基于51单片机饮水机温度水位控制无线蓝牙APP控制报警系统设计(程序+原理图+PCB源文件+Proteus仿真+参考论文+开题报告+元器件清单等)

方案的选择 方案一&#xff1a;采用51单片机作为控制核心&#xff0c;配合无线蓝牙模块、水温加热模块继电器开关、基于Dallas单线数字式的DS18B20温度传感器模块、蜂鸣器报警模块、按键模块、LCD1602液晶显示器模块、晶振电路模块、复位电路模块以及电源模块为一体构成无线水…

winsw使用——将Nginx和Jar包注册到WIN服务

文章目录 1.winsw介绍2.注册Nginx到win服务2.1 首先将下载的winsw下并改名2.2 nginx-service.exe.config配置2.3 nginx-service.xml配置2.4 nginx-service安装到服务 3.注册Jar包到win服务3.1 复制winsw文件并改名3.2 创建xml配置文件3.3 执行安装命令 1.winsw介绍 Windows Se…

ChatGPT Prompt Engineering for Developers from DeepLearning.AI

链接&#xff1a;https://learn.deeplearning.ai/chatgpt-prompt-eng/lesson/1/introduction In this course, there are some example codes that you can already run in Jupyter Notebook. Below, I will write down the core knowledge points (how to build a prompt and…

CSS基础学习--4 创建式样

一、插入样式表的几种方法&#xff1f; 外部样式表内部样式表内联样式 二、外部样式表 使用前提&#xff1a;当样式需要应用于很多页面时&#xff0c;外部样式表将是理想的选择。 在使用外部样式表的情况下&#xff0c;你可以通过改变一个文件来改变整个站点的外观。每个页…