[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)
4분 36초경부터 본인 클라이언트 플레이어 이동은 클라이언트에서 직접 처리하고 서버로부터 응답받은 위치로 더 이상 동기화를 하지 않도록 처리한다면, 실제로 서버에서 이동 검증을 할 때 HandleMove의 CanGo가 false가 되는 경우라면 롤백 프로토콜을 정의해서 대응해야될까요?
제가 StatScaleFloat에 대해 제대로 이해하고 있는 것인지 헷갈려 질문드립니다! StatScaleFloat은 percent type의 스탯에 의해 default value를 조절하고 싶은 스탯을 의미하는 것으로 이해를 하였습니다. 그렇다면 예를 들어 "공격력"이라는 스탯이 있다고 할 때, 해당 스탯을 percent type의 스탯만을 통해 조절하고 싶을 때는 StatScaleFloat를 써도 되지만 그와 동시에 그냥 Bonus Value를 부여하고 싶을 때는 어떻게 해야 할지 헷갈리고 있는 듯 합니다. 아마 제가 이해를 잘 못하고 있는 건가 싶기는 한데 코드를 반복해서 검토해도 감을 잡기가 힘들어 질문드려봅니다. 그리고 좋은 강의 감사드립니다~
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
@PutMapping("/user") public void updateUser(@RequestBody UserUpdateRequest request){ String readSql = "select * from user where id=?"; String sql = "update user set name=? where id=?"; jdbcTemplate.update(sql, request.getName(), request.getId()); } 웹페이지에서 update를 발생시켜서 put 요청이 올라 왔을때 UserUpdateRequest dto에 id와 name이 들어 간다는건 웹에서 요청이 올라왔을때 json에 이미 해당 name에 대한 id 정보가 있다는 거죠? id는 db에서 자동적으로 생성해 준다고 했었는데, 이 id를 웹에서는 어떻게 알고 있나요?
1. 현재 학습 진도 몇 챕터/몇 강을 수강 중이신가요? 4-8강 2. 어려움을 겪는 부분 어느 부분에서 막히셨나요? chapter4/_2_event_with_participant 폴더의 EventJoinService 객체의 메서드 코드에 대한 질문입니다. 코드의 어떤 로직이 이해가 안 되시나요? @Transactional public void joinEvent(Long eventId, Long memberId) { Event event = eventRepository.findById(eventId) .orElseThrow(() -> new EntityNotFoundException("이벤트를 찾을 수 없습니다.")); Member member = memberRepository.findById(memberId) .orElseThrow(() -> new EntityNotFoundException("회원을 찾을 수 없습니다.")); // save()를 호출하지 않아도 Dirty Checking에 의해 Update 쿼리가 나가지 않나요? event.increaseParticipants(); eventRepository.save(event); EventParticipant participant = EventParticipant.builder() .event(event) .member(member) .build(); participantRepository.save(participant); } } 코드 블럭의 주석 란에 질문을 적어놓았습니다. 저 상황에서 save() 를 호출하는 이유가 궁금합니다. JPA 엔티티의 상태 변경분에 대한 쿼리는 트랜잭션 커밋 후, 자동으로 나가는 것으로 알고 있습니다. 혹시, 제가 잘못 알고 있는건지 궁금합니다.
안녕하세요 토비님!! 강의를 완강하고 제 프로젝트를 리팩토링하면서 피드백받고싶은점이 생겨 질문글을 올립니다. Repository Port를 기술에 종속시키지 않기 위해 Adapter에서 JPA, MyBatis, QueryDSL을 조합하는 구조를 선택했는데, 이 설계 방향이 적절한지 조언을 구하고 싶습니다. 현재 구조 core/ └── domain/ └── application/ └── required/ ← Port 인터페이스 └── ~Repository adapter/ └── persistence/ ├── ~RepositoryAdapter ← Port 구현체 ├── ~JpaRepository ← Spring Data JPA └── ~MybatisMapper ← Mybatis 매퍼 인터페이스 의존 관계 [Service] → [Repository] ←impl― [RepositoryAdapter] → [JpaRepository] → [MybatisMapper] → [JPAQueryFactory] (core) (core) (adapter) (adapter) 예시 @Repository @RequiredArgsConstructor public class ItemRepositoryAdapter implements ItemRepository { private final ItemJpaRepository itemJpaRepository; private final ItemMybatisMapper itemMybatisMapper; @Override public List<Item> findBySearchRequest(ItemSearchRequest request) { return itemMybatisMapper.findBySearchRequest(request) .stream() .map(Item::from) .toList(); } @Override public List<Item> saveAll(List<Item> items) { return itemJpaRepository.saveAll(items); } } @Repository @RequiredArgsConstructor public class AuctionRepositoryAdapter implements AuctionRepository { private final JPAQueryFactory jpaQueryFactory; private final AuctionJpaRepository auctionJpaRepository; @Override public void deleteAllByRegionAndRealmId(RegionType region, Long realmId) { QAuction qAuction = QAuction.auction; BooleanBuilder filter = new BooleanBuilder(); filter.and(qAuction.region.eq(region)); if (realmId == null) { filter.and(qAuction.realmId.isNull()); } else { filter.and(qAuction.realmId.eq(realmId)); } jpaQueryFactory.delete(qAuction) .where(filter) .execute(); } @Override public int saveAll(List<Auction> auctions) { if (auctions.isEmpty()) return 0; return auctionJpaRepository.saveAll(auctions).size(); } } 이 구조를 선택한 이유 동적 쿼리, 벌크 연산 등 JPA만으로 해결하기 어려운 케이스가 있어 MyBatis와 QueryDSL을 병행 사용하고 있습니다. 일반적인 방식인 Port 인터페이스가 Spring Data JPA Repository를 상속하는 구조를 채택하지 않은 이유: MyBatis나 QueryDSL 기반 구현체를 만들 수 없음 CustomRepository 인터페이스를 별도로 만들어야 하는 복잡도 증가 현재 방식의 장점: Port 인터페이스가 순수 Java 인터페이스로 유지됨 RepositoryAdapter에서 상황에 맞는 기술을 자유롭게 조합 가능 추가 인터페이스 없이 단순한 구조 유지 저는 현재 구조가 의존 관계도 외부에서 내부로 향하고 테스트도 쉬워서 괜찮다고 생각하는데 토비님의 생각도 듣고싶습니다!! 좋은 강의 감사합니다!!
[Rookiss AI Creative GameDev - Live] Unity Indie & UE5 Tech Lab (2026년 1월 반)
안녕하세요. 카운터스트라이크 소스 분석중 AAModularCharacter 내에 PreInitializeComponents, BeginPlay, EndPlay 등 함수에 UGameFrameworkComponentManager 를 통한 작업들을 보았는데 이것들이 정확히 어떠한 행동을 위한것인지 알기가 어려워 문의 드립니다. 혹시 간략하게나마 게임 피쳐에서 어떤 이벤트가 발생했을때 얘가 이러이러한 역활을 한다 이런식으로라도 혹시 알 수 있을까요?
[Rookiss AI Creative GameDev - Live] Unity Indie & UE5 Tech Lab (2026년 1월 반)
안녕하세요. 올려주신 소스를 보고 따라 만들어 보던 중 질문 드립니다. 카운터스트라이크 소스에서 WorldSetting 을 C++ 로 커스텀 작성하신 (CommonWorldSettings) 월드세팅클래스로 가져오시던데 기존 월드 세팅의 변경은 에디터 -> 프로젝트 세팅 에서 직접 바꾸면 되는걸까요? 아니라고 한다면 C++ 코드 어느부분에서 월드세팅을 커스텀 월드세팅으로 변경해야 할까요?
package hellojpa; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class Member { @Id private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } package hellojpa; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Member member = new Member(); member.setId(1L); member.setName("HelloA"); em.persist(member); tx.commit(); em.close(); emf.close(); } } C:\Users\User\.jdks\temurin-21.0.9\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2025.2.2\lib\idea_rt.jar=65054" -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath C:\study\ex1-hello-jpa\ex1-hello-jpa\target\classes;C:\Users\User\.m2\repository\javax\xml\bind\jaxb-api\2.3.0\jaxb-api-2.3.0.jar;C:\Users\User\.m2\repository\org\hibernate\hibernate-entitymanager\ 5.3.10.Final \ hibernate-entitymanager-5.3.10.Final .jar;C:\Users\User\.m2\repository\org\jboss\logging\jboss-logging\ 3.3.2.Final \ jboss-logging-3.3.2.Final .jar;C:\Users\User\.m2\repository\org\hibernate\hibernate-core\ 5.3.10.Final \ hibernate-core-5.3.10.Final .jar;C:\Users\User\.m2\repository\org\javassist\javassist\3.23.2-GA\javassist-3.23.2-GA.jar;C:\Users\User\.m2\repository\antlr\antlr\2.7.7\antlr-2.7.7.jar;C:\Users\User\.m2\repository\org\jboss\jandex\ 2.0.5.Final \ jandex-2.0.5.Final .jar;C:\Users\User\.m2\repository\com\fasterxml\classmate\1.3.4\classmate-1.3.4.jar;C:\Users\User\.m2\repository\javax\activation\javax.activation-api\1.2.0\javax.activation-api-1.2.0.jar;C:\Users\User\.m2\repository\org\dom4j\dom4j\2.1.1\dom4j-2.1.1.jar;C:\Users\User\.m2\repository\org\hibernate\common\hibernate-commons-annotations\ 5.0.4.Final \ hibernate-commons-annotations-5.0.4.Final .jar;C:\Users\User\.m2\repository\javax\persistence\javax.persistence-api\2.2\javax.persistence-api-2.2.jar;C:\Users\User\.m2\repository\net\bytebuddy\byte-buddy\1.9.5\byte-buddy-1.9.5.jar;C:\Users\User\.m2\repository\org\jboss\spec\javax\transaction\jboss-transaction-api_1.2_spec\ 1.1.1.Final \jboss-transaction-api_1.2_ spec-1.1.1.Final .jar;C:\Users\User\.m2\repository\com\h2database\h2\1.4.199\h2-1.4.199.jar hellojpa.JpaMain 1월 13, 2026 3:42:37 오후 org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation INFO: HHH000204: Processing PersistenceUnitInfo [ name: hello ...] 1월 13, 2026 3:42:37 오후 org.hibernate.Version logVersion INFO: HHH000412: Hibernate Core { 5.3.10.Final } 1월 13, 2026 3:42:37 오후 org.hibernate.cfg.Environment <clinit> INFO: HHH000206: hibernate.properties not found 1월 13, 2026 3:42:37 오후 org.hibernate.annotations.common.reflection.java .JavaReflectionManager <clinit> INFO: HCANN000001: Hibernate Commons Annotations { 5.0.4.Final } 1월 13, 2026 3:42:38 오후 org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator initiateService WARN: HHH000181: No appropriate connection provider encountered, assuming application will be supplying connections 1월 13, 2026 3:42:38 오후 org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator initiateService WARN: HHH000342: Could not obtain connection to query metadata : The application must supply JDBC connections 1월 13, 2026 3:42:38 오후 org.hibernate.dialect.Dialect <init> INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect 1월 13, 2026 3:42:38 오후 org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl makeLobCreatorBuilder INFO: HHH000422: Disabling contextual LOB creation as connection was null Exception in thread "main" java.lang.UnsupportedOperationException: The application must supply JDBC connections at org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl.getConnection(UserSuppliedConnectionProviderImpl.java:44) at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:35) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:106) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:136) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:254) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:262) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:236) at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:86) at hellojpa.JpaMain.main(JpaMain.java:16) Process finished with exit code 1 이거 에러 발생한 이유가 뭘까요? 강의 러닝타임은 11분대입니다.
[AI 시대의 게임 개발을 지탱하는 기술들] 홍사부의 디아블로1 PCG 던전 생성 알고리즘
지금 6강을 듣고 있는데요 솔직히 말해서 지금까지 무슨 얘기를 하는지 하나도 모르겠어요. 많은 강의를 들었지만 이렇게 당황스러운 적은 처음인데요... 일단 저는 PCG가 뭔지 이걸 왜 사용하고 어떤 원리인지 알고 싶지만 이런 기본 개념에 관한 설명이 하나도 없네요. 제가 답답해서 검색으로 찾아봤습니다. 그리고 Room, Chamber도 그냥 텍스트로만 설명해주셨는데 이것도 헷갈리고요, 그 이후의 내용은 당연히 이해하기 너무 힘듭니다. 17번 강의 봤는데 오히려 여기 내용이 1강으로 소개 되어야 하는거 아닌가요? 코드 설명도 하나 씩 작성하면서 풀어내는 방식이 아닌 전체 프로젝트를 던져주고 갑자기 가운데 부분부터 설명하시던데 무슨 얘기를 하는지 도무지 알 수가 없더군요. 강의 소개에서 사전 지식 부분에 Unity사용법과 C#만 알며 된다고 하셨는데 강의 내용은 이 조건과 많이 동떨어져 있어 보입니다. 가르치기 위한 강의보다는 본인이 진행한 프로젝트를 소개하는 영상같은 느낌이 더 듭니다. 수강평이 아닌 질문게시판에 글을 작성한이유는 이 후의 내용도 계속 이런 방식인지, 저처럼 PCG(?) 던전생성알고리즘관련 지식이 전무한 사람은 수강이 어려운 건지 궁금합니다.
안녕하세요! 11. 그래프와 인접행렬 강의를 듣다가 질문이 생겨 글을 남깁니다. 가중치 방향 그래프에서 가중치가 0인 간선이 문제 특성상 의미가 있을 경우 가중치가 0인 간선을 자바로 표현하는 방법이 있을까요? 기존처럼 0으로 표현해 버리면 간선이 없는 경우와 구분하기 어려울 것 같아서요. 검색 해보니 그런 경우에는 double 타입 행렬을 선언하고 간선이 없을 때 Double.POSITIVE_INFINITY 를 쓰는 것 같긴 한데 맞는 방법일까요? 그런 기법이 코딩테스트 풀 때 사용되는지도 궁금합니다.
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용] update하고 응답할 때 어차피 request dto에 응답할 파라메터 값이 담겨져있는데 해당 값을 response dto에 할당해서 응답하면 되지 않을까요? 즉 제가 구상한 코드는 다음과 같습니다. @Operation(summary = "회원 수정") @PutMapping("{id}") public UpdateMemberResponse updateMemberV1(@Validated @RequestBody MemberUpdateDTO memberUpdateDTO, BindingResult bindingResult, @PathVariable("id") Long id){ memberService.update(memberUpdateDTO, id); return new UpdateMemberResponse(id, memberUpdateDTO.getName(), memberUpdateDTO.getCity(), memberUpdateDTO.getStreet(), memberUpdateDTO.getZipcode()); } 굳이 컨트롤러단에서 memberService.findOne(id)를 select문을 날려서 호출해서 준영속상태의 Member 엔티티의 값을 response dto에 할당하는 이유가 있을까요?
안녕하세요. 이전에 성남시 멘토링 진행할 때 업무에 치여 제대로 진행하지 못했었는데, 그 때도 느꼈지만 확실히 설명이 깔끔하고 좋으십니다. 이 강의 이후 다른 강의도 마저 들어보려고 합니다. 질문 드릴 내용은, UGS 기능 자체는 좋으나 요금제 기준이 어느정도인지 아직 감이 제대로 오지 않습니다. 실제 요금제 표 봤을때 읽기,쓰기 월 100만회까지 무료 -> 그 뒤 추가 요금 발생 등 내용은 확인했는데. 1. industry 라이센스가 있는 회사에서 unity cloud/ugs를 도입했을때 요금적으로 부담이 없을지 (콘텐츠로 요금제를 충당할 수 있을만큼 돈 벌었을 때부터 요금이 발생할거다. 등) 주관적인 내용. 2. 개인으로 1인~소규모 인디 개발을 할 때 UGS를 도입한다면 이 경우에도 게임으로 돈을 벌었다. 싶을 때부터 요금이 발생할 것인지 혹여 요금제에서는 확인하지 못하였으나, 1번 경우에 런타임 요금제가 있는지. 요금에 관련된 주관적인 + 아시는 내용이 있다면 듣고 싶습니다. 감사합니다.